From 25706dc41c5fac6aee87f5d8422688c2eb1efecc Mon Sep 17 00:00:00 2001 From: sid597 Date: Mon, 22 Dec 2025 13:55:58 +0530 Subject: [PATCH 1/2] add new setting component for feature flag --- .../settings/BlockPropFeatureFlagPanel.tsx | 37 +++++++++++++++++++ apps/roam/src/utils/manageFeatureFlag.ts | 27 ++++++++++++++ apps/roam/src/utils/zodSchemaForSettings.ts | 8 ++++ 3 files changed, 72 insertions(+) create mode 100644 apps/roam/src/components/settings/BlockPropFeatureFlagPanel.tsx create mode 100644 apps/roam/src/utils/manageFeatureFlag.ts create mode 100644 apps/roam/src/utils/zodSchemaForSettings.ts diff --git a/apps/roam/src/components/settings/BlockPropFeatureFlagPanel.tsx b/apps/roam/src/components/settings/BlockPropFeatureFlagPanel.tsx new file mode 100644 index 000000000..cd6e0986d --- /dev/null +++ b/apps/roam/src/components/settings/BlockPropFeatureFlagPanel.tsx @@ -0,0 +1,37 @@ +import { getFeatureFlag, setFeatureFlag } from "~/utils/manageFeatureFlag"; +import { type FeatureFlags } from "~/utils/zodSchemaForSettings"; +import { Checkbox } from "@blueprintjs/core"; +import Description from "roamjs-components/components/Description"; +import idToTitle from "roamjs-components/util/idToTitle"; +import React, { useState } from "react"; + +export const BlockPropFeatureFlagPanel = ({ + title, + description, + featureKey, +}: { + title: string; + description: string; + featureKey: keyof FeatureFlags; +}) => { + const [value, setValue] = useState(() => getFeatureFlag(featureKey)); + + const handleChange = (e: React.ChangeEvent) => { + const { checked } = e.target; + setFeatureFlag(featureKey, checked); + setValue(checked); + }; + + return ( + + {idToTitle(title)} + + + } + /> + ); +}; diff --git a/apps/roam/src/utils/manageFeatureFlag.ts b/apps/roam/src/utils/manageFeatureFlag.ts new file mode 100644 index 000000000..c495773a5 --- /dev/null +++ b/apps/roam/src/utils/manageFeatureFlag.ts @@ -0,0 +1,27 @@ +import { FeatureFlagsSchema, type FeatureFlags } from "./zodSchemaForSettings"; +import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/data/blockPropsSettingsConfig"; +import { + setBlockPropBasedSettings, + getBlockPropBasedSettings, +} from "~/utils/settingsUsingBlockProps"; + +export const getFeatureFlag = (key: keyof FeatureFlags): boolean => { + const featureFlagKey = TOP_LEVEL_BLOCK_PROP_KEYS.featureFlags; + + const { blockProps } = getBlockPropBasedSettings({ + keys: [featureFlagKey], + }); + + const flags = FeatureFlagsSchema.parse(blockProps || {}); + + return flags[key]; +}; + +export const setFeatureFlag = ( + key: keyof FeatureFlags, + value: boolean, +): void => { + const featureFlagKey = TOP_LEVEL_BLOCK_PROP_KEYS.featureFlags; + + void setBlockPropBasedSettings({ keys: [featureFlagKey, key], value }); +}; diff --git a/apps/roam/src/utils/zodSchemaForSettings.ts b/apps/roam/src/utils/zodSchemaForSettings.ts new file mode 100644 index 000000000..f05a394e9 --- /dev/null +++ b/apps/roam/src/utils/zodSchemaForSettings.ts @@ -0,0 +1,8 @@ +import { z } from "zod"; + +/* eslint-disable @typescript-eslint/naming-convention */ +export const FeatureFlagsSchema = z.object({ +}); +/* eslint-disable @typescript-eslint/naming-convention */ + +export type FeatureFlags = z.infer; From d583c3d6db4cb7bab31cf94e2a1cac01f3e98dbc Mon Sep 17 00:00:00 2001 From: sid597 Date: Mon, 22 Dec 2025 14:37:31 +0530 Subject: [PATCH 2/2] validate on write --- apps/roam/src/utils/manageFeatureFlag.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/roam/src/utils/manageFeatureFlag.ts b/apps/roam/src/utils/manageFeatureFlag.ts index c495773a5..b17653927 100644 --- a/apps/roam/src/utils/manageFeatureFlag.ts +++ b/apps/roam/src/utils/manageFeatureFlag.ts @@ -1,3 +1,4 @@ +import { z } from "zod"; import { FeatureFlagsSchema, type FeatureFlags } from "./zodSchemaForSettings"; import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/data/blockPropsSettingsConfig"; import { @@ -23,5 +24,10 @@ export const setFeatureFlag = ( ): void => { const featureFlagKey = TOP_LEVEL_BLOCK_PROP_KEYS.featureFlags; - void setBlockPropBasedSettings({ keys: [featureFlagKey, key], value }); + const validatedValue = z.boolean().parse(value); + + void setBlockPropBasedSettings({ + keys: [featureFlagKey, key], + value: validatedValue, + }); };