diff --git a/frontend/common/constants.ts b/frontend/common/constants.ts index f2ad5e48daa1..bc5668307da1 100644 --- a/frontend/common/constants.ts +++ b/frontend/common/constants.ts @@ -260,6 +260,18 @@ const Constants = { 'category': 'User', 'event': `User oauth ${type}`, }), + 'ONBOARDING_AI_CONNECT': { + 'category': 'Onboarding', + 'event': 'Onboarding AI connect used', + }, + 'ONBOARDING_FLAG_TOGGLED': { + 'category': 'Onboarding', + 'event': 'Onboarding flag toggled', + }, + 'ONBOARDING_SNIPPET_COPIED': { + 'category': 'Onboarding', + 'event': 'Onboarding snippet copied', + }, 'REFERRER_CONVERSION': (referrer: string) => ({ 'category': 'Referrer', 'event': `${referrer} converted`, diff --git a/frontend/common/utils/getOnboardingVariant.ts b/frontend/common/utils/getOnboardingVariant.ts new file mode 100644 index 000000000000..c684e37ac7fc --- /dev/null +++ b/frontend/common/utils/getOnboardingVariant.ts @@ -0,0 +1,13 @@ +import Utils from './utils' + +export type OnboardingVariant = 'control' | 'single_page' + +// The served variant name picks the arm ('control' is the reserved key the +// API reports for the default arm). Enabled with no variant is the +// pre-conversion boolean flag, which means the new flow. +export const isSinglePageOnboarding = (): boolean => + Utils.getFlagsmithHasFeature('onboarding_quickstart_flow') && + Utils.getFlagsmithVariant('onboarding_quickstart_flow') !== 'control' + +export const getOnboardingVariant = (): OnboardingVariant => + isSinglePageOnboarding() ? 'single_page' : 'control' diff --git a/frontend/common/utils/utils.tsx b/frontend/common/utils/utils.tsx index f987451a981c..1d718f5c7d3e 100644 --- a/frontend/common/utils/utils.tsx +++ b/frontend/common/utils/utils.tsx @@ -382,6 +382,9 @@ const Utils = Object.assign({}, BaseUtils, { getFlagsmithValue(key: string) { return flagsmith.getValue(key) }, + getFlagsmithVariant(key: string) { + return flagsmith.getAllFlags()[key]?.variant + }, getIdentitiesEndpoint(_project: ProjectType) { const project = _project || ProjectStore.model diff --git a/frontend/web/components/pages/onboarding/GettingStartedGate.tsx b/frontend/web/components/pages/onboarding/GettingStartedGate.tsx index e819504723c4..4374867fd57a 100644 --- a/frontend/web/components/pages/onboarding/GettingStartedGate.tsx +++ b/frontend/web/components/pages/onboarding/GettingStartedGate.tsx @@ -1,19 +1,20 @@ -import React, { FC } from 'react' -import Utils from 'common/utils/utils' +import React, { FC, useEffect } from 'react' +import { + getOnboardingVariant, + isSinglePageOnboarding, +} from 'common/utils/getOnboardingVariant' +import API from 'project/api' import GettingStartedPage from 'components/pages/GettingStartedPage' import OnboardingFlow from './OnboardingFlow' -// Gates /getting-started: renders the new onboarding flow when the -// `onboarding_quickstart_flow` flag is on, otherwise the existing page. -// -// Deliberately a flat file, not a folder + barrel - a one-line route gate with -// no styles or sub-parts, the documented exception to the component-folder -// convention (frontend/CLAUDE.md rule 8). -const GettingStartedGate: FC = () => - Utils.getFlagsmithHasFeature('onboarding_quickstart_flow') ? ( - - ) : ( - - ) +const GettingStartedGate: FC = () => { + const variant = getOnboardingVariant() + + useEffect(() => { + API.trackTraits({ onboarding_variant: variant }) + }, [variant]) + + return isSinglePageOnboarding() ? : +} export default GettingStartedGate diff --git a/frontend/web/components/pages/onboarding/OnboardingConnectPanel/ConnectWithAiPanel.tsx b/frontend/web/components/pages/onboarding/OnboardingConnectPanel/ConnectWithAiPanel.tsx index 626a1000f44e..df2bc0e2c1dd 100644 --- a/frontend/web/components/pages/onboarding/OnboardingConnectPanel/ConnectWithAiPanel.tsx +++ b/frontend/web/components/pages/onboarding/OnboardingConnectPanel/ConnectWithAiPanel.tsx @@ -7,6 +7,7 @@ import { useCopyFeedback } from 'components/pages/onboarding/hooks/useCopyFeedba export type ConnectWithAiPanelProps = { environmentKey: string featureName: string + onCopyPrompt?: () => void } // "Connect with AI" tab: an agent-agnostic prompt the user pastes into their @@ -18,6 +19,7 @@ export type ConnectWithAiPanelProps = { const ConnectWithAiPanel: FC = ({ environmentKey, featureName, + onCopyPrompt, }) => { const { copied, copy } = useCopyFeedback() @@ -39,7 +41,14 @@ Detect my stack, install the SDK, and wire ${featureName} into one place. Then r {aiPrompt} -