diff --git a/app/auth-portal/src/pages/ProfilePage.vue b/app/auth-portal/src/pages/ProfilePage.vue index 2eeee048a7..a2c83dd35e 100644 --- a/app/auth-portal/src/pages/ProfilePage.vue +++ b/app/auth-portal/src/pages/ProfilePage.vue @@ -230,6 +230,7 @@ const saveHandler = async () => { const completeProfileReq = await authStore.COMPLETE_PROFILE({}); if (completeProfileReq.result.success) { if (authStore.user?.emailVerified) { + tracker.trackEvent("workspace_launcher_widget_click"); window.location.href = `${API_HTTP_URL}/workspaces/${workspacesStore.defaultWorkspace.id}/go`; } else { // eslint-disable-next-line @typescript-eslint/no-floating-promises diff --git a/app/auth-portal/src/pages/WorkspaceDetailsPage.vue b/app/auth-portal/src/pages/WorkspaceDetailsPage.vue index 76acb868c5..d660f4a065 100644 --- a/app/auth-portal/src/pages/WorkspaceDetailsPage.vue +++ b/app/auth-portal/src/pages/WorkspaceDetailsPage.vue @@ -58,6 +58,7 @@ , required: true }, }); +const urlInputRef = ref>(); + const { validationState, validationMethods } = useValidatedInputGroup(); const members = computed(() => workspacesStore.selectedWorkspaceMembers); @@ -295,6 +298,23 @@ const createWorkspace = async () => { draftWorkspace.instanceUrl = "https://app.systeminit.com"; } else if (createWorkspaceType.value === "local") { draftWorkspace.instanceUrl = "localhost:8080"; + } else { + if (draftWorkspace.instanceUrl.includes("app.systeminit")) { + // Can't create a Remote URL workspace with our URL! + urlInputRef.value?.setError( + 'You cannot use an "app.systeminit" URL for a Remote URL Workspace. Use "Managed By System Initiative" instead.', + ); + return; + } else if ( + draftWorkspace.instanceUrl.includes("localhost") || + draftWorkspace.instanceUrl.includes("127.0.0.1") + ) { + // Can't create a Remote URL workspace with localhost! + urlInputRef.value?.setError( + 'You cannot use a "localhost" URL for a Remote URL Workspace. Use "Local Dev Instance" instead.', + ); + return; + } } if (validationMethods.hasError()) return; diff --git a/app/web/src/store/workspaces.store.ts b/app/web/src/store/workspaces.store.ts index ef5a695d67..adcb8f6116 100644 --- a/app/web/src/store/workspaces.store.ts +++ b/app/web/src/store/workspaces.store.ts @@ -19,12 +19,14 @@ type WorkspaceExportSummary = { createdAt: IsoDateString; }; +type InstanceEnvType = "LOCAL" | "PRIVATE" | "SI"; + type AuthApiWorkspace = { creatorUserId: string; displayName: string; id: WorkspacePk; pk: WorkspacePk; // not actually in the response, but we backfill - // instanceEnvType: "LOCAL" // not used yet... + instanceEnvType: InstanceEnvType; instanceUrl: string; role: "OWNER" | "EDITOR"; token: string; diff --git a/bin/auth-api/src/routes/workspace.routes.ts b/bin/auth-api/src/routes/workspace.routes.ts index 7356a8850c..46ccba8dfa 100644 --- a/bin/auth-api/src/routes/workspace.routes.ts +++ b/bin/auth-api/src/routes/workspace.routes.ts @@ -1,5 +1,6 @@ import { nanoid } from "nanoid"; import { z } from 'zod'; +import { InstanceEnvType } from "@prisma/client"; import { ApiError } from "../lib/api-error"; import { getCache, setCache } from "../lib/cache"; import { getUserById, refreshUserAuth0Profile } from "../services/users.service"; @@ -81,7 +82,17 @@ router.post("/workspaces/new", async (ctx) => { displayName: z.string(), })); - const workspaceDetails = await createWorkspace(ctx.state.authUser, reqBody.instanceUrl, reqBody.displayName); + let workspaceEnvType; + if (reqBody.instanceUrl === "https://app.systeminit.com") { + workspaceEnvType = InstanceEnvType.SI; + } else if (reqBody.instanceUrl === "localhost:8080") { + workspaceEnvType = InstanceEnvType.LOCAL; + } else { + workspaceEnvType = InstanceEnvType.PRIVATE; + } + + const workspaceDetails = await + createWorkspace(ctx.state.authUser, workspaceEnvType, reqBody.instanceUrl, reqBody.displayName); ctx.body = { workspaces: await getUserWorkspaces(ctx.state.authUser.id), diff --git a/bin/auth-api/src/services/users.service.ts b/bin/auth-api/src/services/users.service.ts index b13de68a6e..985a03a5cc 100644 --- a/bin/auth-api/src/services/users.service.ts +++ b/bin/auth-api/src/services/users.service.ts @@ -1,7 +1,7 @@ import _ from 'lodash'; import { ulid } from "ulidx"; import * as Auth0 from 'auth0'; -import { Prisma, PrismaClient } from '@prisma/client'; +import { InstanceEnvType, Prisma, PrismaClient } from '@prisma/client'; import { createWorkspace } from "./workspaces.service"; import { LATEST_TOS_VERSION_ID } from './tos.service'; @@ -115,8 +115,8 @@ export async function createOrUpdateUserFromAuth0Details(auth0UserData: Auth0.Us lastName: user.lastName, }); - // create a default dev workspace - await createWorkspace(user); + // create a default saas workspace + await createWorkspace(user, InstanceEnvType.SI, "https://app.systeminit.com", `${user.nickname}'s Production Workspace`); } return user; diff --git a/bin/auth-api/src/services/workspaces.service.ts b/bin/auth-api/src/services/workspaces.service.ts index 7ab20f0979..eba45fe541 100644 --- a/bin/auth-api/src/services/workspaces.service.ts +++ b/bin/auth-api/src/services/workspaces.service.ts @@ -29,14 +29,15 @@ export async function getWorkspaceById(id: WorkspaceId) { export async function createWorkspace( creatorUser: User, - instanceUrl = "http://localhost:8080", - displayName = `${creatorUser.nickname}'s dev workspace`, + workspaceEnvType: InstanceEnvType, + instanceUrl: string, + displayName: string, ) { const newWorkspace = await prisma.workspace.create({ data: { id: ulid(), token: ulid(), - instanceEnvType: InstanceEnvType.LOCAL, + instanceEnvType: workspaceEnvType, instanceUrl, displayName, creatorUserId: creatorUser.id, diff --git a/bin/auth-api/test/auth-routes.test.ts b/bin/auth-api/test/auth-routes.test.ts index 4cb600aa25..c5516f01ae 100644 --- a/bin/auth-api/test/auth-routes.test.ts +++ b/bin/auth-api/test/auth-routes.test.ts @@ -2,6 +2,7 @@ import t from 'tap'; import { expect } from 'chai'; import _ from 'lodash'; +import { InstanceEnvType } from '@prisma/client'; import { request } from './helpers/supertest-agents'; import { testSuiteAfter, testSuiteBefore } from './helpers/test-suite-hooks'; import { mockAuth0TokenExchange } from './helpers/auth0-mocks'; @@ -94,7 +95,7 @@ t.test('Auth routes', async () => { if (!user) { t.bailout("User Fetch has failed"); } - const workspace = await createWorkspace(user!); + const workspace = await createWorkspace(user!, InstanceEnvType.SI, "https://app.systeminit.com", `${user!.nickname}'s Testing Workspace`); const sdfToken = createSdfAuthToken(authData.userId, workspace.id); await request.get('/whoami') .set('cookie', `si-auth=${sdfToken}`) diff --git a/bin/auth-api/test/helpers/dummy-factory.ts b/bin/auth-api/test/helpers/dummy-factory.ts index 12d9dcd0b9..5258350d9e 100644 --- a/bin/auth-api/test/helpers/dummy-factory.ts +++ b/bin/auth-api/test/helpers/dummy-factory.ts @@ -1,4 +1,6 @@ -import { Prisma, PrismaClient, User } from '@prisma/client'; +import { + InstanceEnvType, Prisma, PrismaClient, User, +} from '@prisma/client'; import { ulid } from 'ulidx'; import _ from 'lodash'; import { saveTosAgreement, LATEST_TOS_VERSION_ID } from '../../src/services/tos.service'; @@ -50,7 +52,7 @@ export async function createDummyUser(options?: { await saveTosAgreement(user, LATEST_TOS_VERSION_ID, '1.2.3.4'); } - const workspace = await createWorkspace(user); + const workspace = await createWorkspace(user, InstanceEnvType.SI, "https://app.systeminit.com", `${user.nickname}'s Testing Workspace`); return { user, workspace }; }