From af722128e8df76988d347595fb19d9609757e4df Mon Sep 17 00:00:00 2001 From: arcticfly <41524992+arcticfly@users.noreply.github.com> Date: Wed, 23 Aug 2023 18:18:56 -0700 Subject: [PATCH] Use feature flags to control beta features (#185) * Use feature flags to control beta features * Remove references to beta env variable --- app/Dockerfile | 1 - app/src/components/nav/AppShell.tsx | 6 ++++-- app/src/env.mjs | 2 -- app/src/state/featureFlags.ts | 20 ++++++++++++++++++++ app/src/state/store.ts | 5 ++++- app/src/utils/analytics/posthog.tsx | 11 ++++++++++- 6 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 app/src/state/featureFlags.ts diff --git a/app/Dockerfile b/app/Dockerfile index 0ca2846..3627886 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -23,7 +23,6 @@ ARG NEXT_PUBLIC_SOCKET_URL ARG NEXT_PUBLIC_HOST ARG NEXT_PUBLIC_SENTRY_DSN ARG SENTRY_AUTH_TOKEN -ARG NEXT_PUBLIC_FF_SHOW_BETA_FEATURES WORKDIR /code COPY --from=deps /code/node_modules ./node_modules diff --git a/app/src/components/nav/AppShell.tsx b/app/src/components/nav/AppShell.tsx index 7606ad2..a9cddc4 100644 --- a/app/src/components/nav/AppShell.tsx +++ b/app/src/components/nav/AppShell.tsx @@ -18,11 +18,11 @@ import { IoStatsChartOutline } from "react-icons/io5"; import { RiHome3Line, RiFlaskLine } from "react-icons/ri"; import { FaRobot } from "react-icons/fa"; import { signIn, useSession } from "next-auth/react"; -import { env } from "~/env.mjs"; import ProjectMenu from "./ProjectMenu"; import NavSidebarOption from "./NavSidebarOption"; import IconLink from "./IconLink"; import { BetaModal } from "./BetaModal"; +import { useAppStore } from "~/state/store"; const Divider = () => ; @@ -167,6 +167,8 @@ export default function AppShell({ } }, [requireAuth, user, authLoading]); + const flags = useAppStore((s) => s.featureFlags.featureFlags); + return ( <> @@ -178,7 +180,7 @@ export default function AppShell({ {children} - {requireBeta && !env.NEXT_PUBLIC_FF_SHOW_BETA_FEATURES && } + {requireBeta && !flags.betaAccess && } ); } diff --git a/app/src/env.mjs b/app/src/env.mjs index 433b95b..e47966b 100644 --- a/app/src/env.mjs +++ b/app/src/env.mjs @@ -46,7 +46,6 @@ export const env = createEnv({ NEXT_PUBLIC_SOCKET_URL: z.string().url().default("http://localhost:3318"), NEXT_PUBLIC_HOST: z.string().url().default("http://localhost:3000"), NEXT_PUBLIC_SENTRY_DSN: z.string().optional(), - NEXT_PUBLIC_FF_SHOW_BETA_FEATURES: z.string().optional(), }, /** @@ -68,7 +67,6 @@ export const env = createEnv({ NEXT_PUBLIC_SENTRY_DSN: process.env.NEXT_PUBLIC_SENTRY_DSN, SENTRY_AUTH_TOKEN: process.env.SENTRY_AUTH_TOKEN, OPENPIPE_API_KEY: process.env.OPENPIPE_API_KEY, - NEXT_PUBLIC_FF_SHOW_BETA_FEATURES: process.env.NEXT_PUBLIC_FF_SHOW_BETA_FEATURES, SENDER_EMAIL: process.env.SENDER_EMAIL, SMTP_HOST: process.env.SMTP_HOST, SMTP_PORT: process.env.SMTP_PORT, diff --git a/app/src/state/featureFlags.ts b/app/src/state/featureFlags.ts new file mode 100644 index 0000000..8c89db9 --- /dev/null +++ b/app/src/state/featureFlags.ts @@ -0,0 +1,20 @@ +import { type SliceCreator } from "./store"; + +export type FeatureFlagsSlice = { + featureFlags: { + betaAccess: boolean; + }; + setFeatureFlags: (flags: string[] | undefined) => void; +}; + +export const createFeatureFlagsSlice: SliceCreator = (set) => ({ + featureFlags: { + betaAccess: false, + }, + setFeatureFlags: (flags) => + set((state) => { + state.featureFlags.featureFlags = { + betaAccess: flags?.includes("betaAccess") ?? false, + }; + }), +}); diff --git a/app/src/state/store.ts b/app/src/state/store.ts index d6d7fba..bbd3ce1 100644 --- a/app/src/state/store.ts +++ b/app/src/state/store.ts @@ -11,7 +11,8 @@ import { type APIClient } from "~/utils/api"; import { type PersistedState, persistOptions } from "./persist"; import { type SelectedLogsSlice, createSelectedLogsSlice } from "./selectedLogsSlice"; import { type LogFiltersSlice, createLogFiltersSlice } from "./logFiltersSlice"; -import { createColumnVisibilitySlice, type ColumnVisibilitySlice } from "./columnVisiblitySlice"; +import { type ColumnVisibilitySlice, createColumnVisibilitySlice } from "./columnVisiblitySlice"; +import { type FeatureFlagsSlice, createFeatureFlagsSlice } from "./featureFlags"; enableMapSet(); @@ -28,6 +29,7 @@ export type State = { selectedLogs: SelectedLogsSlice; logFilters: LogFiltersSlice; columnVisibility: ColumnVisibilitySlice; + featureFlags: FeatureFlagsSlice; }; export type SliceCreator = StateCreator; @@ -62,6 +64,7 @@ const useBaseStore = create { }; }, [router.events]); + const setFeatureFlags = useAppStore((s) => s.featureFlags.setFeatureFlags); + const activeFlags = useActiveFeatureFlags(); + useEffect(() => { + if (activeFlags) { + setFeatureFlags(activeFlags); + } + }, [activeFlags, setFeatureFlags]); + useEffect(() => { if (env.NEXT_PUBLIC_POSTHOG_KEY && inBrowser && session && session.user) { posthog.init(env.NEXT_PUBLIC_POSTHOG_KEY, {