From 8fa8a02d13bd15fb0f5b7cac15ca134ce0d4312a Mon Sep 17 00:00:00 2001 From: sid597 Date: Thu, 21 May 2026 21:41:38 +0530 Subject: [PATCH 1/2] Cache discourse node type reads --- .../settings/DiscourseNodeConfigPanel.tsx | 3 +++ .../components/settings/utils/accessors.ts | 20 +++++++++++++++++++ .../utils/migrateLegacyToBlockProps.ts | 5 +++++ apps/roam/src/utils/discourseNodeTypeCache.ts | 8 ++++++++ apps/roam/src/utils/findDiscourseNode.ts | 10 +++++++++- 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 apps/roam/src/utils/discourseNodeTypeCache.ts diff --git a/apps/roam/src/components/settings/DiscourseNodeConfigPanel.tsx b/apps/roam/src/components/settings/DiscourseNodeConfigPanel.tsx index f2bda0b83..01a2c289d 100644 --- a/apps/roam/src/components/settings/DiscourseNodeConfigPanel.tsx +++ b/apps/roam/src/components/settings/DiscourseNodeConfigPanel.tsx @@ -22,6 +22,7 @@ import setBlockProps from "~/utils/setBlockProps"; import { DiscourseNodeSchema } from "./utils/zodSchema"; import { getGlobalSettings, setGlobalSetting } from "./utils/accessors"; import { GLOBAL_KEYS } from "./utils/settingKeys"; +import { invalidateDiscourseNodeTypeCaches } from "~/utils/discourseNodeTypeCache"; type DiscourseNodeConfigPanelProps = React.ComponentProps< CustomField["options"]["component"] @@ -60,6 +61,7 @@ const DiscourseNodeConfigPanel: React.FC = ({ await window.roamAlphaAPI.deletePage({ page: { uid }, }); + invalidateDiscourseNodeTypeCaches(); setNodes((prevNodes) => prevNodes.filter((nn) => nn.type !== uid)); refreshConfigTree(); setDeleteConfirmation(null); @@ -117,6 +119,7 @@ const DiscourseNodeConfigPanel: React.FC = ({ format, }), ); + invalidateDiscourseNodeTypeCaches(); setNodes([ ...nodes, { diff --git a/apps/roam/src/components/settings/utils/accessors.ts b/apps/roam/src/components/settings/utils/accessors.ts index 46fd70342..9c7dc6178 100644 --- a/apps/roam/src/components/settings/utils/accessors.ts +++ b/apps/roam/src/components/settings/utils/accessors.ts @@ -24,6 +24,10 @@ import { } from "~/utils/getExportSettings"; import { getSuggestiveModeConfigAndUids } from "~/utils/getSuggestiveModeConfigSettings"; import { getLeftSidebarSettings } from "~/utils/getLeftSidebarSettings"; +import { + getDiscourseNodeTypeCacheVersion, + invalidateDiscourseNodeTypeCaches, +} from "~/utils/discourseNodeTypeCache"; import { DG_BLOCK_PROP_SETTINGS_PAGE_TITLE, @@ -767,6 +771,10 @@ export const setFeatureFlag = ( keys: [STATIC_TOP_LEVEL_ENTRIES.featureFlags.key, key], value: validatedValue, }); + + if (key === "Use new settings store") { + invalidateDiscourseNodeTypeCaches(); + } }; export const getGlobalSettings = (): GlobalSettings => { @@ -1023,6 +1031,7 @@ export const setDiscourseNodeSetting = ( } setBlockPropAtPath(pageUid, keys, value); + invalidateDiscourseNodeTypeCaches(); }; const addConditionUids = (conditions: SchemaCondition[]): Condition[] => @@ -1131,7 +1140,17 @@ const migrateNodeBlockProps = ( return migrated; }; +let allDiscourseNodesCache: { + version: number; + nodes: DiscourseNode[]; +} | null = null; + export const getAllDiscourseNodes = (): DiscourseNode[] => { + const cacheVersion = getDiscourseNodeTypeCacheVersion(); + if (allDiscourseNodesCache?.version === cacheVersion) { + return allDiscourseNodesCache.nodes; + } + const results = window.roamAlphaAPI.data.fast.q(` [:find ?uid ?title (pull ?page [:block/props]) :where @@ -1191,5 +1210,6 @@ export const getAllDiscourseNodes = (): DiscourseNode[] => { } } + allDiscourseNodesCache = { version: cacheVersion, nodes }; return nodes; }; diff --git a/apps/roam/src/components/settings/utils/migrateLegacyToBlockProps.ts b/apps/roam/src/components/settings/utils/migrateLegacyToBlockProps.ts index e026982a0..da29fa11b 100644 --- a/apps/roam/src/components/settings/utils/migrateLegacyToBlockProps.ts +++ b/apps/roam/src/components/settings/utils/migrateLegacyToBlockProps.ts @@ -23,6 +23,7 @@ import { getPersonalSettingsKey, } from "./zodSchema"; import type { z } from "zod"; +import { invalidateDiscourseNodeTypeCaches } from "~/utils/discourseNodeTypeCache"; const LOG_PREFIX = "[DG BlockProps Migration]"; const GRAPH_MIGRATION_MARKER = "Block props migrated"; @@ -63,11 +64,13 @@ const migrateSection = ({ blockUid, schema, legacyData, + onWrite, }: { label: string; blockUid: string; schema: z.ZodTypeAny; legacyData: Record; + onWrite?: () => void; }): boolean => { const currentProps = getBlockProps(blockUid); @@ -103,6 +106,7 @@ const migrateSection = ({ } setBlockProps(blockUid, parsedLegacy, false); + onWrite?.(); console.log(`${LOG_PREFIX} ${label}: migrated`); return true; }; @@ -156,6 +160,7 @@ const migrateDiscourseNodes = async (): Promise => { blockUid: nodePageUid, schema: DiscourseNodeSchema, legacyData, + onWrite: invalidateDiscourseNodeTypeCaches, }) ) { allOk = false; diff --git a/apps/roam/src/utils/discourseNodeTypeCache.ts b/apps/roam/src/utils/discourseNodeTypeCache.ts new file mode 100644 index 000000000..f5dc59a00 --- /dev/null +++ b/apps/roam/src/utils/discourseNodeTypeCache.ts @@ -0,0 +1,8 @@ +let discourseNodeTypeCacheVersion = 0; + +export const invalidateDiscourseNodeTypeCaches = (): void => { + discourseNodeTypeCacheVersion += 1; +}; + +export const getDiscourseNodeTypeCacheVersion = (): number => + discourseNodeTypeCacheVersion; diff --git a/apps/roam/src/utils/findDiscourseNode.ts b/apps/roam/src/utils/findDiscourseNode.ts index e0af95981..0c3e5ced3 100644 --- a/apps/roam/src/utils/findDiscourseNode.ts +++ b/apps/roam/src/utils/findDiscourseNode.ts @@ -1,8 +1,10 @@ import getDiscourseNodes, { type DiscourseNode } from "./getDiscourseNodes"; import matchDiscourseNode from "./matchDiscourseNode"; import type { SettingsSnapshot } from "~/components/settings/utils/accessors"; +import { getDiscourseNodeTypeCacheVersion } from "./discourseNodeTypeCache"; -const discourseNodeTypeCache: Record = {}; +let discourseNodeTypeCache: Record = {}; +let discourseNodeTypeCacheVersion = -1; const findDiscourseNode = ({ uid, @@ -15,6 +17,12 @@ const findDiscourseNode = ({ nodes?: DiscourseNode[]; snapshot?: SettingsSnapshot; }): DiscourseNode | false => { + const currentCacheVersion = getDiscourseNodeTypeCacheVersion(); + if (discourseNodeTypeCacheVersion !== currentCacheVersion) { + discourseNodeTypeCache = {}; + discourseNodeTypeCacheVersion = currentCacheVersion; + } + if (typeof discourseNodeTypeCache[uid] !== "undefined") { return discourseNodeTypeCache[uid]; } From 3378eff05c37a3c98cb98f4abc5556d21e6eaa98 Mon Sep 17 00:00:00 2001 From: sid597 Date: Tue, 26 May 2026 16:00:14 +0530 Subject: [PATCH 2/2] Extract feature flag keys into FEATURE_FLAG_KEYS const Replaces repeated "Use new settings store" string literals in accessors.ts with a typed FEATURE_FLAG_KEYS constant, following the existing *_KEYS convention in settingKeys.ts. Makes typos a compile error. --- .../src/components/settings/utils/accessors.ts | 17 +++++++++++------ .../components/settings/utils/settingKeys.ts | 8 ++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/apps/roam/src/components/settings/utils/accessors.ts b/apps/roam/src/components/settings/utils/accessors.ts index 9c7dc6178..9ddcadd10 100644 --- a/apps/roam/src/components/settings/utils/accessors.ts +++ b/apps/roam/src/components/settings/utils/accessors.ts @@ -44,7 +44,12 @@ import { type DiscourseNodeSettings, type Condition as SchemaCondition, } from "./zodSchema"; -import { PERSONAL_KEYS, QUERY_KEYS, GLOBAL_KEYS } from "./settingKeys"; +import { + FEATURE_FLAG_KEYS, + PERSONAL_KEYS, + QUERY_KEYS, + GLOBAL_KEYS, +} from "./settingKeys"; const isRecord = (value: unknown): value is Record => typeof value === "object" && value !== null && !Array.isArray(value); @@ -720,7 +725,7 @@ export const getFeatureFlag = (key: keyof FeatureFlags): boolean => { }; export const isNewSettingsStoreEnabled = (): boolean => { - return getFeatureFlag("Use new settings store"); + return getFeatureFlag(FEATURE_FLAG_KEYS.useNewSettingsStore); }; export const readAllLegacyFeatureFlags = (): Partial => { @@ -728,7 +733,7 @@ export const readAllLegacyFeatureFlags = (): Partial => { for (const [key, reader] of Object.entries(FEATURE_FLAG_LEGACY_MAP)) { flags[key as keyof FeatureFlags] = reader(); } - flags["Use new settings store"] = false; + flags[FEATURE_FLAG_KEYS.useNewSettingsStore] = false; return flags; }; @@ -772,7 +777,7 @@ export const setFeatureFlag = ( value: validatedValue, }); - if (key === "Use new settings store") { + if (key === FEATURE_FLAG_KEYS.useNewSettingsStore) { invalidateDiscourseNodeTypeCaches(); } }; @@ -888,7 +893,7 @@ export const bulkReadSettings = (): SettingsSnapshot => { const featureFlags = FeatureFlagsSchema.parse(featureFlagsProps || {}); - if (!featureFlags["Use new settings store"]) { + if (!featureFlags[FEATURE_FLAG_KEYS.useNewSettingsStore]) { return { featureFlags, globalSettings: readAllLegacyGlobalSettings() as GlobalSettings, @@ -975,7 +980,7 @@ export const getDiscourseNodeSetting = ( nodeType: string, keys: string[], ): T | undefined => { - if (!bulkReadSettings().featureFlags["Use new settings store"]) { + if (!bulkReadSettings().featureFlags[FEATURE_FLAG_KEYS.useNewSettingsStore]) { return getLegacyDiscourseNodeSetting(nodeType, keys) as T | undefined; } diff --git a/apps/roam/src/components/settings/utils/settingKeys.ts b/apps/roam/src/components/settings/utils/settingKeys.ts index be61da1a4..827f26100 100644 --- a/apps/roam/src/components/settings/utils/settingKeys.ts +++ b/apps/roam/src/components/settings/utils/settingKeys.ts @@ -1,4 +1,5 @@ import type { + FeatureFlags, PersonalSettings, QuerySettings, GlobalSettings, @@ -10,6 +11,13 @@ import type { SuggestiveRules, } from "./zodSchema"; +export const FEATURE_FLAG_KEYS = { + enableLeftSidebar: "Enable left sidebar", + duplicateNodeAlertEnabled: "Duplicate node alert enabled", + suggestiveModeOverlayEnabled: "Suggestive mode overlay enabled", + useNewSettingsStore: "Use new settings store", +} as const satisfies Record; + export const PERSONAL_KEYS = { discourseContextOverlay: "Discourse context overlay", textSelectionPopup: "Text selection popup",