From 615c0ec9058694a8a1328fd60a6d8930c6cc6a35 Mon Sep 17 00:00:00 2001 From: armaan Date: Wed, 17 Jun 2026 19:00:54 +0000 Subject: [PATCH] Hide sub-apps from dashboard onboarding wizard Filter out apps with a parentAppId (e.g. clickmaps, session-replays, fraud-protection) from ONBOARDING_APP_IDS so they don't appear in the project onboarding app-selection step. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../project-onboarding-wizard.test.tsx | 10 +++++++++- .../new-project/page-client-parts/shared.ts | 4 ++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx index 8e097d760..145853e25 100644 --- a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx +++ b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/project-onboarding-wizard.test.tsx @@ -141,7 +141,7 @@ vi.mock("./link-existing-onboarding", () => ({ import { ProjectOnboardingWizard } from "./project-onboarding-wizard"; import { normalizeProjectOnboardingState, orderedAppIds, REQUIRED_APP_IDS } from "./shared"; -import { ALL_APPS } from "@hexclave/shared/dist/apps/apps-config"; +import { ALL_APPS, getParentAppId, type AppId } from "@hexclave/shared/dist/apps/apps-config"; afterEach(() => { cleanup(); @@ -171,6 +171,14 @@ describe("ProjectOnboardingWizard", () => { } }); + it("does not offer sub-apps during app selection", () => { + const subAppIds = (Object.keys(ALL_APPS) as AppId[]).filter((appId) => getParentAppId(appId) != null); + + for (const subAppId of subAppIds) { + expect(orderedAppIds()).not.toContain(subAppId); + } + }); + it("completes onboarding automatically after Stripe setup returns successfully", async () => { const setStatus = vi.fn(async () => {}); const onComplete = vi.fn(); diff --git a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts index e1afc8e4e..3e1fdd22e 100644 --- a/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts +++ b/apps/dashboard/src/app/(main)/(protected)/(outside-dashboard)/new-project/page-client-parts/shared.ts @@ -1,6 +1,6 @@ import { hexclaveAppInternalsSymbol } from "@/lib/hexclave-app-internals"; import { AdminOwnedProject } from "@hexclave/next"; -import { ALL_APPS, type AppId } from "@hexclave/shared/dist/apps/apps-config"; +import { ALL_APPS, getParentAppId, type AppId } from "@hexclave/shared/dist/apps/apps-config"; import { projectOnboardingStatusValues, type ProjectOnboardingStatus } from "@hexclave/shared/dist/schema-fields"; import { sharedProviders } from "@hexclave/shared/dist/utils/oauth"; import { stringCompare } from "@hexclave/shared/dist/utils/strings"; @@ -23,7 +23,7 @@ export const SIGN_IN_METHODS: Array<{ id: SignInMethod, label: string }> = [ export const REQUIRED_APP_IDS: AppId[] = ["authentication", "emails"]; export const PRIMARY_APP_IDS: AppId[] = ["authentication", "emails", "payments", "analytics"]; export const ALL_APP_IDS = Object.keys(ALL_APPS) as AppId[]; -export const ONBOARDING_APP_IDS = ALL_APP_IDS.filter((appId) => ALL_APPS[appId].stage !== "alpha"); +export const ONBOARDING_APP_IDS = ALL_APP_IDS.filter((appId) => ALL_APPS[appId].stage !== "alpha" && getParentAppId(appId) == null); export const OAUTH_SIGN_IN_METHODS = ["google", "github", "microsoft"] satisfies SignInMethod[]; export const SHARED_OAUTH_SIGN_IN_METHODS = sharedProviders.filter((provider): provider is (typeof sharedProviders)[number] & SignInMethod => { return OAUTH_SIGN_IN_METHODS.some((method) => method === provider);