diff --git a/frontend/src/layout/navigation-3000/sidepanel/panels/sidePanelSettingsLogic.tsx b/frontend/src/layout/navigation-3000/sidepanel/panels/sidePanelSettingsLogic.tsx index 53682a2556b53..162b6ba9343c9 100644 --- a/frontend/src/layout/navigation-3000/sidepanel/panels/sidePanelSettingsLogic.tsx +++ b/frontend/src/layout/navigation-3000/sidepanel/panels/sidePanelSettingsLogic.tsx @@ -43,7 +43,7 @@ export const sidePanelSettingsLogic = kea([ listeners(({ actions, values }) => ({ openSettingsPanel: ({ settingsLogicProps }) => { - if (!values.featureFlags[FEATURE_FLAGS.POSTHOG_3000]) { + if (values.featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'control') { LemonDialog.open({ title: 'Settings', content: , diff --git a/frontend/src/layout/navigation-3000/themeLogic.ts b/frontend/src/layout/navigation-3000/themeLogic.ts index 8d238bf5631f3..22b482d34662c 100644 --- a/frontend/src/layout/navigation-3000/themeLogic.ts +++ b/frontend/src/layout/navigation-3000/themeLogic.ts @@ -36,7 +36,7 @@ export const themeLogic = kea([ } // Dark mode is a PostHog 3000 feature // User-saved preference is used when set, oterwise we fall back to the system value - return featureFlags[FEATURE_FLAGS.POSTHOG_3000] + return featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test' ? user?.theme_mode ? user.theme_mode === 'dark' : darkModeSystemPreference diff --git a/frontend/src/layout/navigation/TopBar/NotebookButton.tsx b/frontend/src/layout/navigation/TopBar/NotebookButton.tsx index 87e08761ffd06..215616a66faf2 100644 --- a/frontend/src/layout/navigation/TopBar/NotebookButton.tsx +++ b/frontend/src/layout/navigation/TopBar/NotebookButton.tsx @@ -7,7 +7,7 @@ import { notebookPanelLogic } from 'scenes/notebooks/NotebookPanel/notebookPanel export function NotebookButton(): JSX.Element { const { visibility } = useValues(notebookPanelLogic) const { toggleVisibility } = useActions(notebookPanelLogic) - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') const overrides3000: Partial = is3000 ? { diff --git a/frontend/src/layout/navigation/TopBar/SitePopover.tsx b/frontend/src/layout/navigation/TopBar/SitePopover.tsx index 930497e3403e4..8c7e5060145ee 100644 --- a/frontend/src/layout/navigation/TopBar/SitePopover.tsx +++ b/frontend/src/layout/navigation/TopBar/SitePopover.tsx @@ -300,7 +300,7 @@ export function SitePopoverOverlay(): JSX.Element { )} - + diff --git a/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx b/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx index f0762c235657d..f6e25140bea89 100644 --- a/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx +++ b/frontend/src/lib/components/CommandPalette/commandPaletteLogic.tsx @@ -251,7 +251,7 @@ export const commandPaletteLogic = kea([ selectors({ isUsingCmdKSearch: [ (selectors) => [selectors.featureFlags], - (featureFlags) => featureFlags[FEATURE_FLAGS.POSTHOG_3000], + (featureFlags) => featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test', ], isSqueak: [ (selectors) => [selectors.input], @@ -1008,7 +1008,7 @@ export const commandPaletteLogic = kea([ actions.registerCommand(createDashboard) actions.registerCommand(shareFeedback) actions.registerCommand(debugCopySessionRecordingURL) - if (values.featureFlags[FEATURE_FLAGS.POSTHOG_3000]) { + if (values.featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test') { actions.registerCommand(toggleTheme) actions.registerCommand(toggleHedgehogMode) actions.registerCommand(shortcuts) diff --git a/frontend/src/lib/components/PageHeader.tsx b/frontend/src/lib/components/PageHeader.tsx index b5be77f167ce5..27b4773d25947 100644 --- a/frontend/src/lib/components/PageHeader.tsx +++ b/frontend/src/lib/components/PageHeader.tsx @@ -27,12 +27,13 @@ export function PageHeader({ delimited, notebookProps, }: PageHeaderProps): JSX.Element | null { - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') const { actionsContainer } = useValues(breadcrumbsLogic) return ( <> {!is3000 && ( + // eslint-disable-next-line react/forbid-dom-props
{!is3000 && diff --git a/frontend/src/lib/components/Support/supportLogic.ts b/frontend/src/lib/components/Support/supportLogic.ts index cae978a3c3a6e..e5be094824d64 100644 --- a/frontend/src/lib/components/Support/supportLogic.ts +++ b/frontend/src/lib/components/Support/supportLogic.ts @@ -336,7 +336,7 @@ export const supportLogic = kea([ actionToUrl(({ values }) => { return { closeSupportForm: () => { - if (values.featureFlags[FEATURE_FLAGS.POSTHOG_3000]) { + if (values.featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test') { return } diff --git a/frontend/src/lib/hooks/use3000Body.ts b/frontend/src/lib/hooks/use3000Body.ts index 2b7ba96747d70..6ada43cb822c3 100644 --- a/frontend/src/lib/hooks/use3000Body.ts +++ b/frontend/src/lib/hooks/use3000Body.ts @@ -6,7 +6,7 @@ import { themeLogic } from '~/layout/navigation-3000/themeLogic' import { useFeatureFlag } from './useFeatureFlag' export function use3000Body(): void { - const is3000 = !!useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') const { isDarkModeOn } = useValues(themeLogic) useEffect(() => { diff --git a/frontend/src/lib/hooks/useFeatureFlag.ts b/frontend/src/lib/hooks/useFeatureFlag.ts index 721805a362395..df0e8bb99341c 100644 --- a/frontend/src/lib/hooks/useFeatureFlag.ts +++ b/frontend/src/lib/hooks/useFeatureFlag.ts @@ -2,8 +2,12 @@ import { useValues } from 'kea' import { FEATURE_FLAGS } from 'lib/constants' import { featureFlagLogic } from 'lib/logic/featureFlagLogic' -export const useFeatureFlag = (flag: keyof typeof FEATURE_FLAGS): boolean => { +export const useFeatureFlag = (flag: keyof typeof FEATURE_FLAGS, match?: string): boolean => { const { featureFlags } = useValues(featureFlagLogic) + if (match) { + return featureFlags[FEATURE_FLAGS[flag]] === match + } + return !!featureFlags[FEATURE_FLAGS[flag]] } diff --git a/frontend/src/lib/lemon-ui/LemonMenu/LemonMenu.tsx b/frontend/src/lib/lemon-ui/LemonMenu/LemonMenu.tsx index e3b251ad78e49..5e4d4def77a1c 100644 --- a/frontend/src/lib/lemon-ui/LemonMenu/LemonMenu.tsx +++ b/frontend/src/lib/lemon-ui/LemonMenu/LemonMenu.tsx @@ -131,7 +131,7 @@ export function LemonMenuOverlay({ items, tooltipPlacement, itemsRef }: LemonMen const { featureFlags } = useValues(featureFlagLogic) const sectionsOrItems = useMemo(() => normalizeItems(items), [items]) - const buttonSize = featureFlags[FEATURE_FLAGS.POSTHOG_3000] ? 'small' : 'medium' + const buttonSize = featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test' ? 'small' : 'medium' return sectionsOrItems.length > 0 && isLemonMenuSection(sectionsOrItems[0]) ? ( ({ HTMLDivElement, HTMLLIElement >(value, 200) - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') let buttonProps = {} diff --git a/frontend/src/lib/lemon-ui/Link/Link.tsx b/frontend/src/lib/lemon-ui/Link/Link.tsx index 6c41cb1db64e9..bbbaacb3f42ec 100644 --- a/frontend/src/lib/lemon-ui/Link/Link.tsx +++ b/frontend/src/lib/lemon-ui/Link/Link.tsx @@ -87,7 +87,7 @@ export const Link: React.FC> = Reac href: typeof to === 'string' ? to : undefined, }) - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') const { openDocsPage } = useActions(sidePanelDocsLogic) const onClick = (event: React.MouseEvent): void => { diff --git a/frontend/src/lib/logic/featureFlagLogic.ts b/frontend/src/lib/logic/featureFlagLogic.ts index 592ea0f6646d7..ac1d3f160c13c 100644 --- a/frontend/src/lib/logic/featureFlagLogic.ts +++ b/frontend/src/lib/logic/featureFlagLogic.ts @@ -1,4 +1,5 @@ import { actions, afterMount, kea, path, reducers } from 'kea' +import { FEATURE_FLAGS } from 'lib/constants' import { getAppContext } from 'lib/utils/getAppContext' import posthog from 'posthog-js' @@ -22,7 +23,24 @@ function notifyFlagIfNeeded(flag: string, flagState: string | boolean | undefine function getPersistedFeatureFlags(appContext: AppContext | undefined = getAppContext()): FeatureFlagsSet { const persistedFeatureFlags = appContext?.persisted_feature_flags || [] - return Object.fromEntries(persistedFeatureFlags.map((f) => [f, true])) + /** :HACKY: Handle experiment (non-boolean) feature flag for 3000. */ + let has3000Flag = false + const flags = Object.fromEntries( + persistedFeatureFlags.map((f) => { + if (f === FEATURE_FLAGS.POSTHOG_3000) { + has3000Flag = true + return [f, 'test'] + } else { + return [f, true] + } + }) + ) + + if (!has3000Flag) { + flags[FEATURE_FLAGS.POSTHOG_3000] = 'control' + } + + return flags } function spyOnFeatureFlags(featureFlags: FeatureFlagsSet): FeatureFlagsSet { diff --git a/frontend/src/scenes/App.tsx b/frontend/src/scenes/App.tsx index a12a690e5fb53..e403138c07f86 100644 --- a/frontend/src/scenes/App.tsx +++ b/frontend/src/scenes/App.tsx @@ -155,7 +155,7 @@ function AppScene(): JSX.Element | null { ) : null } - const Navigation = featureFlags[FEATURE_FLAGS.POSTHOG_3000] ? Navigation3000 : NavigationClassic + const Navigation = featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test' ? Navigation3000 : NavigationClassic return ( <> diff --git a/frontend/src/scenes/authentication/InviteSignup.tsx b/frontend/src/scenes/authentication/InviteSignup.tsx index 0128e51c01a68..aa87fca3c9d9d 100644 --- a/frontend/src/scenes/authentication/InviteSignup.tsx +++ b/frontend/src/scenes/authentication/InviteSignup.tsx @@ -193,7 +193,7 @@ function AuthenticatedAcceptInvite({ invite }: { invite: PrevalidatedInvite }): function UnauthenticatedAcceptInvite({ invite }: { invite: PrevalidatedInvite }): JSX.Element { const { signup, isSignupSubmitting } = useValues(inviteSignupLogic) const { preflight } = useValues(preflightLogic) - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') return ( { - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') return is3000 ? { diff --git a/frontend/src/scenes/dashboard/Dashboard.tsx b/frontend/src/scenes/dashboard/Dashboard.tsx index 6ff62dd3dea72..edf3a90b7a73e 100644 --- a/frontend/src/scenes/dashboard/Dashboard.tsx +++ b/frontend/src/scenes/dashboard/Dashboard.tsx @@ -170,9 +170,8 @@ function DashboardScene(): JSX.Element {
)}
- {placement !== DashboardPlacement.Export && !featureFlags[FEATURE_FLAGS.POSTHOG_3000] && ( - - )} + {placement !== DashboardPlacement.Export && + featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'control' && } )} diff --git a/frontend/src/scenes/dashboard/EmptyDashboardComponent.tsx b/frontend/src/scenes/dashboard/EmptyDashboardComponent.tsx index cb2db4be65f5f..3cd01c1de2c4d 100644 --- a/frontend/src/scenes/dashboard/EmptyDashboardComponent.tsx +++ b/frontend/src/scenes/dashboard/EmptyDashboardComponent.tsx @@ -12,7 +12,7 @@ import { DASHBOARD_CANNOT_EDIT_MESSAGE } from './DashboardHeader' import { dashboardLogic } from './dashboardLogic' function SkeletonCard({ children, active }: { children: React.ReactNode; active: boolean }): JSX.Element { - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') const rounded = is3000 ? 'rounded-md' : 'rounded' return ( diff --git a/frontend/src/scenes/notebooks/IconNotebook.tsx b/frontend/src/scenes/notebooks/IconNotebook.tsx index bdc4a14becc46..d18e92347d946 100644 --- a/frontend/src/scenes/notebooks/IconNotebook.tsx +++ b/frontend/src/scenes/notebooks/IconNotebook.tsx @@ -3,7 +3,7 @@ import { useFeatureFlag } from 'lib/hooks/useFeatureFlag' import { IconNotebook as IconNotebookLegacy, LemonIconProps } from 'lib/lemon-ui/icons' export function IconNotebook(props: LemonIconProps): JSX.Element { - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') return is3000 ? : } diff --git a/frontend/src/scenes/notebooks/Notebook/NotebookListMini.tsx b/frontend/src/scenes/notebooks/Notebook/NotebookListMini.tsx index 25ac0088e1ad5..94757955f30d1 100644 --- a/frontend/src/scenes/notebooks/Notebook/NotebookListMini.tsx +++ b/frontend/src/scenes/notebooks/Notebook/NotebookListMini.tsx @@ -16,7 +16,7 @@ export type NotebookListMiniProps = { export function NotebookListMini({ selectedNotebookId }: NotebookListMiniProps): JSX.Element { const { notebooks, notebookTemplates } = useValues(notebooksModel) - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') const selectedTitle = selectedNotebookId === 'scratchpad' diff --git a/frontend/src/scenes/notebooks/NotebookCanvasScene.tsx b/frontend/src/scenes/notebooks/NotebookCanvasScene.tsx index e6db7608942d4..b0a9b56f8fa4d 100644 --- a/frontend/src/scenes/notebooks/NotebookCanvasScene.tsx +++ b/frontend/src/scenes/notebooks/NotebookCanvasScene.tsx @@ -25,7 +25,7 @@ export function NotebookCanvas(): JSX.Element { const { duplicateNotebook } = useActions(notebookLogic(logicProps)) - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') if (!is3000) { return Canvas mode requires PostHog 3000} /> diff --git a/frontend/src/scenes/notebooks/NotebookPanel/notebookPanelLogic.ts b/frontend/src/scenes/notebooks/NotebookPanel/notebookPanelLogic.ts index 7f77123b42c53..98bc881454e75 100644 --- a/frontend/src/scenes/notebooks/NotebookPanel/notebookPanelLogic.ts +++ b/frontend/src/scenes/notebooks/NotebookPanel/notebookPanelLogic.ts @@ -67,7 +67,7 @@ export const notebookPanelLogic = kea([ })), selectors(({ cache, actions }) => ({ - is3000: [(s) => [s.featureFlags], (featureFlags) => featureFlags[FEATURE_FLAGS.POSTHOG_3000]], + is3000: [(s) => [s.featureFlags], (featureFlags) => featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test'], visibility: [ (s) => [s.selectedTab, s.sidePanelOpen, s.popoverVisibility, s.is3000], diff --git a/frontend/src/scenes/notebooks/NotebookScene.tsx b/frontend/src/scenes/notebooks/NotebookScene.tsx index 0d0b2baa69f5e..e97761af1b97b 100644 --- a/frontend/src/scenes/notebooks/NotebookScene.tsx +++ b/frontend/src/scenes/notebooks/NotebookScene.tsx @@ -41,7 +41,7 @@ export function NotebookScene(): JSX.Element { const { selectedNotebook, visibility } = useValues(notebookPanelLogic) const { featureFlags } = useValues(featureFlagLogic) - const buttonSize = featureFlags[FEATURE_FLAGS.POSTHOG_3000] ? 'small' : 'medium' + const buttonSize = featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test' ? 'small' : 'medium' if (!notebook && !loading && !conflictWarningVisible) { return diff --git a/frontend/src/scenes/persons/personsLogic.tsx b/frontend/src/scenes/persons/personsLogic.tsx index e87d7f3d749f3..a8c68f528ea4b 100644 --- a/frontend/src/scenes/persons/personsLogic.tsx +++ b/frontend/src/scenes/persons/personsLogic.tsx @@ -79,7 +79,7 @@ export const personsLogic = kea([ ...(values.listFilters.properties || []), ...values.hiddenListProperties, ] - if (values.featureFlags[FEATURE_FLAGS.POSTHOG_3000]) { + if (values.featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test') { newFilters.include_total = true // The total count is slow, but needed for infinite loading } if (props.cohort) { diff --git a/frontend/src/scenes/project-homepage/ProjectHomepage.tsx b/frontend/src/scenes/project-homepage/ProjectHomepage.tsx index 7c94b4e570f52..88672c5a5008a 100644 --- a/frontend/src/scenes/project-homepage/ProjectHomepage.tsx +++ b/frontend/src/scenes/project-homepage/ProjectHomepage.tsx @@ -35,7 +35,7 @@ export function ProjectHomepage(): JSX.Element { sceneDashboardChoiceModalLogic({ scene: Scene.ProjectHomepage }) ) - const is3000 = useFeatureFlag('POSTHOG_3000') + const is3000 = useFeatureFlag('POSTHOG_3000', 'test') const headerButtons = ( <> diff --git a/frontend/src/scenes/saved-insights/SavedInsights.tsx b/frontend/src/scenes/saved-insights/SavedInsights.tsx index 239a089cbabbf..7d1cfb8cf913d 100644 --- a/frontend/src/scenes/saved-insights/SavedInsights.tsx +++ b/frontend/src/scenes/saved-insights/SavedInsights.tsx @@ -320,12 +320,13 @@ export function InsightIcon({ insight }: { insight: InsightModel }): JSX.Element export function NewInsightButton({ dataAttr }: NewInsightButtonProps): JSX.Element { const { featureFlags } = useValues(featureFlagLogic) - const overrides3000: Partial = featureFlags[FEATURE_FLAGS.POSTHOG_3000] - ? { - size: 'small', - icon: , - } - : {} + const overrides3000: Partial = + featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test' + ? { + size: 'small', + icon: , + } + : {} return ( { } = useValues(webAnalyticsLogic) const { setWebAnalyticsFilters, setDates } = useActions(webAnalyticsLogic) const { featureFlags } = useValues(featureFlagLogic) - const hasPosthog3000 = featureFlags[FEATURE_FLAGS.POSTHOG_3000] + const hasPosthog3000 = featureFlags[FEATURE_FLAGS.POSTHOG_3000] === 'test' return (