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, {