diff --git a/apps/roam/src/components/settings/AdminPanel.tsx b/apps/roam/src/components/settings/AdminPanel.tsx index d12fd4a12..b0309e40f 100644 --- a/apps/roam/src/components/settings/AdminPanel.tsx +++ b/apps/roam/src/components/settings/AdminPanel.tsx @@ -1,7 +1,6 @@ -import React, { useState, useEffect, useMemo } from "react"; +import React, { useState, useEffect } from "react"; import { Button, - Checkbox, HTMLTable, Alert, Intent, @@ -12,7 +11,6 @@ import { TabId, Tabs, } from "@blueprintjs/core"; -import Description from "roamjs-components/components/Description"; import { Select } from "@blueprintjs/select"; import { getSupabaseContext, @@ -29,15 +27,13 @@ import { import type { DGSupabaseClient } from "@repo/database/lib/client"; import internalError from "~/utils/internalError"; import SuggestiveModeSettings from "./SuggestiveModeSettings"; -import { getFormattedConfigTree } from "~/utils/discourseConfigRef"; -import refreshConfigTree from "~/utils/refreshConfigTree"; -import createBlock from "roamjs-components/writes/createBlock"; -import deleteBlock from "roamjs-components/writes/deleteBlock"; import { setFeatureFlag, getFeatureFlag, + isSyncEnabled, } from "~/components/settings/utils/accessors"; import { FeatureFlagPanel } from "./components/BlockPropSettingPanels"; +import type { FeatureFlags } from "./utils/zodSchema"; const NodeRow = ({ node }: { node: PConceptFull }) => { return ( @@ -258,63 +254,89 @@ const NodeListTab = (): React.ReactElement => { }; const FeatureFlagsTab = (): React.ReactElement => { - const settings = useMemo(() => { - refreshConfigTree(); - return getFormattedConfigTree(); - }, []); - - const [suggestiveModeEnabled, setSuggestiveModeEnabled] = useState( - settings.suggestiveModeEnabled.value || false, + const [isConsentAlertOpen, setIsConsentAlertOpen] = useState(false); + const [isInstructionAlertOpen, setIsInstructionAlertOpen] = useState(false); + const [isFirstSyncEnable, setIsFirstSyncEnable] = useState(false); + const [pendingFeatureKey, setPendingFeatureKey] = useState< + keyof FeatureFlags | null + >(null); + const [duplicateNodeAlertValue, setDuplicateNodeAlertValue] = useState( + getFeatureFlag("Duplicate node alert enabled"), ); - const [suggestiveModeUid, setSuggestiveModeUid] = useState( - settings.suggestiveModeEnabled.uid, + const [suggestiveOverlayValue, setSuggestiveOverlayValue] = useState( + getFeatureFlag("Suggestive mode overlay enabled"), ); - const [isAlertOpen, setIsAlertOpen] = useState(false); - const [isInstructionOpen, setIsInstructionOpen] = useState(false); + + const syncAlreadyEnabled = duplicateNodeAlertValue || suggestiveOverlayValue; + + const ensureSyncEnabled = ( + featureKey: keyof FeatureFlags, + ): Promise => { + if (syncAlreadyEnabled) { + return Promise.resolve(true); + } + setPendingFeatureKey(featureKey); + setIsConsentAlertOpen(true); + return Promise.resolve(false); + }; + + const handleFeatureToggled = ( + checked: boolean, + setter: (v: boolean) => void, + ) => { + setter(checked); + if (checked) { + setIsInstructionAlertOpen(true); + } + }; return (
- { - const checked = (e.target as HTMLInputElement).checked; - if (checked) { - setIsAlertOpen(true); - } else { - if (suggestiveModeUid) { - void deleteBlock(suggestiveModeUid); - setSuggestiveModeUid(undefined); - } - setSuggestiveModeEnabled(false); - setFeatureFlag("Suggestive mode enabled", false); - } - }} - labelElement={ - <> - (BETA) Suggestive mode enabled - Sync Config -> Click on 'Generate & Upload All Node Embeddings'" - } - /> - + ensureSyncEnabled("Duplicate node alert enabled")} + onAfterChange={(checked) => + handleFeatureToggled(checked, setDuplicateNodeAlertValue) + } + /> + + + ensureSyncEnabled("Suggestive mode overlay enabled") + } + onAfterChange={(checked) => + handleFeatureToggled(checked, setSuggestiveOverlayValue) } /> + { - void createBlock({ - parentUid: settings.settingsUid, - node: { text: "(BETA) Suggestive Mode Enabled" }, - }).then((uid) => { - setSuggestiveModeUid(uid); - setSuggestiveModeEnabled(true); - setFeatureFlag("Suggestive mode enabled", true); - setIsAlertOpen(false); - setIsInstructionOpen(true); - }); + if (pendingFeatureKey) { + setFeatureFlag(pendingFeatureKey, true); + if (pendingFeatureKey === "Duplicate node alert enabled") { + setDuplicateNodeAlertValue(true); + } else if ( + pendingFeatureKey === "Suggestive mode overlay enabled" + ) { + setSuggestiveOverlayValue(true); + } + } + setIsConsentAlertOpen(false); + setIsFirstSyncEnable(true); + setIsInstructionAlertOpen(true); + }} + onCancel={() => { + setPendingFeatureKey(null); + setIsConsentAlertOpen(false); }} - onCancel={() => setIsAlertOpen(false)} canEscapeKeyCancel={true} canOutsideClickCancel={true} intent={Intent.PRIMARY} @@ -322,42 +344,40 @@ const FeatureFlagsTab = (): React.ReactElement => { cancelButtonText="Cancel" >

- Enabling Suggestive Mode will send your data (nodes) to our servers - and OpenAI servers to generate embeddings and suggestions. + Enabling this feature will send your data (nodes) to our servers and + OpenAI servers to generate embeddings and suggestions.

Are you sure you want to proceed?

window.location.reload()} - onCancel={() => setIsInstructionOpen(false)} + onCancel={() => { + setIsInstructionAlertOpen(false); + setIsFirstSyncEnable(false); + }} confirmButtonText="Reload Graph" cancelButtonText="Later" intent={Intent.PRIMARY} > -

- If this is the first time enabling it, you will need to generate and - upload all node embeddings to supabase. -

-

- Please reload the graph to see the new 'Suggestive Mode' - tab. -

-

- Then go to Suggestive Mode{" "} - {"-> Sync Config -> Click on 'Generate & Upload All Node Embeddings'"} -

+

Please reload the graph for this change to take effect.

+ {isFirstSyncEnable && ( + <> +

+ If this is the first time enabling sync, you will need to generate + and upload all node embeddings. +

+

+ After reloading, go to Sync mode{" "} + { + "-> Sync config -> Click on 'Generate & Upload All Node Embeddings'" + } +

+ + )}
- -
} /> - {settings.suggestiveModeEnabled.value && ( + {isSyncEnabled() && ( } /> diff --git a/apps/roam/src/components/settings/HomePersonalSettings.tsx b/apps/roam/src/components/settings/HomePersonalSettings.tsx index d1424295c..58738930a 100644 --- a/apps/roam/src/components/settings/HomePersonalSettings.tsx +++ b/apps/roam/src/components/settings/HomePersonalSettings.tsx @@ -1,4 +1,4 @@ -import React, { useMemo, useState } from "react"; +import React, { useState } from "react"; import { OnloadArgs } from "roamjs-components/types"; import { render as renderToast } from "roamjs-components/components/Toast"; import { Label, Dialog, Button, Intent, Classes } from "@blueprintjs/core"; @@ -7,7 +7,6 @@ import { addStyle } from "roamjs-components/dom"; import { NodeMenuTriggerComponent } from "~/components/DiscourseNodeMenu"; import { getOverlayHandler, - getSuggestiveOverlayHandler, onPageRefObserverChange, previewPageRefHandler, } from "~/utils/pageRefObserverHandlers"; @@ -28,7 +27,6 @@ import { getSetting, setSetting } from "~/utils/extensionSettings"; import { enablePostHog, disablePostHog } from "~/utils/posthog"; import KeyboardShortcutInput from "./KeyboardShortcutInput"; import streamlineStyling from "~/styles/streamlineStyling"; -import { getFormattedConfigTree } from "~/utils/discourseConfigRef"; import { PersonalFlagPanel } from "./components/BlockPropSettingPanels"; import migrateRelations from "~/utils/migrateRelations"; import { countReifiedRelations } from "~/utils/createReifiedBlock"; @@ -47,7 +45,6 @@ const enum RelationMigrationDialog { const HomePersonalSettings = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => { const extensionAPI = onloadArgs.extensionAPI; const overlayHandler = getOverlayHandler(onloadArgs); - const settings = useMemo(() => getFormattedConfigTree(), []); const [activeRelationMigration, setActiveRelationMigration] = useState(RelationMigrationDialog.none); const [numExistingRelations, setNumExistingRelations] = useState(0); @@ -152,21 +149,6 @@ const HomePersonalSettings = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => { }); }} /> - {settings.suggestiveModeEnabled?.value && ( - ("suggestive-mode-overlay", false)} - onChange={(checked) => { - void setSetting("suggestive-mode-overlay", checked); - onPageRefObserverChange(getSuggestiveOverlayHandler(onloadArgs))( - checked, - ); - }} - /> - )} - { - const settings = useMemo(() => { - refreshConfigTree(); - return getFormattedConfigTree(); - }, []); const getUid = (key: string) => getSubTree({ parentUid: node.type, @@ -296,7 +291,7 @@ const NodeConfig = ({ } /> - {settings.suggestiveModeEnabled.value && ( + {isSyncEnabled() && ( Promise; onAfterChange?: (checked: boolean) => void; @@ -534,6 +536,7 @@ export const FeatureFlagPanel = ({ settingKeys={[featureKey as string]} setter={featureFlagSetter} initialValue={initialValue} + value={value} disabled={disabled} onBeforeChange={handleBeforeChange} onChange={onAfterChange} diff --git a/apps/roam/src/components/settings/utils/accessors.ts b/apps/roam/src/components/settings/utils/accessors.ts index 6bbf66549..0e116510d 100644 --- a/apps/roam/src/components/settings/utils/accessors.ts +++ b/apps/roam/src/components/settings/utils/accessors.ts @@ -285,6 +285,10 @@ export const getFeatureFlag = (key: keyof FeatureFlags): boolean => { return flags[key]; }; +export const isSyncEnabled = (): boolean => + getFeatureFlag("Duplicate node alert enabled") || + getFeatureFlag("Suggestive mode overlay enabled"); + export const setFeatureFlag = ( key: keyof FeatureFlags, value: boolean, diff --git a/apps/roam/src/components/settings/utils/zodSchema.example.ts b/apps/roam/src/components/settings/utils/zodSchema.example.ts index 4a3f2113b..5700ea47f 100644 --- a/apps/roam/src/components/settings/utils/zodSchema.example.ts +++ b/apps/roam/src/components/settings/utils/zodSchema.example.ts @@ -88,14 +88,14 @@ const discourseNodeSettings: DiscourseNodeSettings = { const featureFlags: FeatureFlags = { "Enable left sidebar": true, - "Suggestive mode enabled": true, "Duplicate node alert enabled": true, + "Suggestive mode overlay enabled": true, }; const defaultFeatureFlags: FeatureFlags = { "Enable left sidebar": false, - "Suggestive mode enabled": false, "Duplicate node alert enabled": false, + "Suggestive mode overlay enabled": false, }; const exportSettings: ExportSettings = { @@ -364,7 +364,6 @@ const personalSettings: PersonalSettings = { "Node search menu trigger": "//", "Discourse tool shortcut": { modifiers: 0, key: "d" }, "Discourse context overlay": true, - "Suggestive mode overlay": true, "Overlay in canvas": false, "Text selection popup": true, "Disable sidebar open": false, @@ -393,7 +392,6 @@ const defaultPersonalSettings: PersonalSettings = { "Node search menu trigger": "", "Discourse tool shortcut": { modifiers: 0, key: "" }, "Discourse context overlay": false, - "Suggestive mode overlay": false, "Overlay in canvas": false, "Text selection popup": true, "Disable sidebar open": false, diff --git a/apps/roam/src/components/settings/utils/zodSchema.ts b/apps/roam/src/components/settings/utils/zodSchema.ts index 190951951..c08ffffb3 100644 --- a/apps/roam/src/components/settings/utils/zodSchema.ts +++ b/apps/roam/src/components/settings/utils/zodSchema.ts @@ -155,8 +155,8 @@ export const DiscourseRelationSchema = z.object({ export const FeatureFlagsSchema = z.object({ "Enable left sidebar": z.boolean().default(false), - "Suggestive mode enabled": z.boolean().default(false), "Duplicate node alert enabled": z.boolean().default(false), + "Suggestive mode overlay enabled": z.boolean().default(false), }); export const ExportSettingsSchema = z.object({ @@ -249,7 +249,6 @@ export const PersonalSettingsSchema = z.object({ .default({ modifiers: 0, key: "" }), "Discourse context overlay": z.boolean().default(false), "Reified relation triples": z.boolean().default(false), - "Suggestive mode overlay": z.boolean().default(false), "Overlay in canvas": z.boolean().default(false), "Text selection popup": z.boolean().default(true), "Disable sidebar open": z.boolean().default(false), diff --git a/apps/roam/src/index.ts b/apps/roam/src/index.ts index acc26eb1d..ab74d4b9c 100644 --- a/apps/roam/src/index.ts +++ b/apps/roam/src/index.ts @@ -31,10 +31,6 @@ import { setSyncActivity, } from "./utils/syncDgNodesToSupabase"; import { initPluginTimer } from "./utils/pluginTimer"; -import { getUidAndBooleanSetting } from "./utils/getExportSettings"; -import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid"; -import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle"; -import { DISCOURSE_CONFIG_PAGE_TITLE } from "./utils/renderNodeConfigPage"; import { getSetting } from "./utils/extensionSettings"; import { initPostHog } from "./utils/posthog"; import { @@ -42,6 +38,7 @@ import { DISALLOW_DIAGNOSTICS, } from "./data/userSettings"; import { initSchema } from "./components/settings/utils/init"; +import { isSyncEnabled } from "./components/settings/utils/accessors"; export const DEFAULT_CANVAS_PAGE_FORMAT = "Canvas/*"; @@ -112,14 +109,7 @@ export default runExtension(async (onloadArgs) => { document.addEventListener("input", discourseNodeSearchTriggerListener); document.addEventListener("selectionchange", nodeCreationPopoverListener); - const isSuggestiveModeEnabled = getUidAndBooleanSetting({ - tree: getBasicTreeByParentUid( - getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE), - ), - text: "(BETA) Suggestive Mode Enabled", - }).value; - - if (isSuggestiveModeEnabled) { + if (isSyncEnabled()) { initializeSupabaseSync(); } diff --git a/apps/roam/src/utils/discourseConfigRef.ts b/apps/roam/src/utils/discourseConfigRef.ts index 24f758269..b152a3930 100644 --- a/apps/roam/src/utils/discourseConfigRef.ts +++ b/apps/roam/src/utils/discourseConfigRef.ts @@ -45,7 +45,6 @@ type FormattedConfigTree = { suggestiveMode: SuggestiveModeConfigWithUids; leftSidebar: LeftSidebarConfig; leftSidebarEnabled: BooleanSetting; - suggestiveModeEnabled: BooleanSetting; }; export const getFormattedConfigTree = (): FormattedConfigTree => { @@ -78,10 +77,6 @@ export const getFormattedConfigTree = (): FormattedConfigTree => { tree: configTreeRef.tree, text: "(BETA) Left Sidebar", }), - suggestiveModeEnabled: getUidAndBooleanSetting({ - tree: configTreeRef.tree, - text: "(BETA) Suggestive Mode Enabled", - }), }; }; export default configTreeRef; diff --git a/apps/roam/src/utils/initializeObserversAndListeners.ts b/apps/roam/src/utils/initializeObserversAndListeners.ts index 0bd4d6c22..a01b15e67 100644 --- a/apps/roam/src/utils/initializeObserversAndListeners.ts +++ b/apps/roam/src/utils/initializeObserversAndListeners.ts @@ -106,21 +106,11 @@ export const initObservers = async ({ const { title, uid } = getTitleAndUidFromHeader(h1); const props = { title, h1, onloadArgs }; - const isSuggestiveModeEnabled = getUidAndBooleanSetting({ - tree: getBasicTreeByParentUid( - getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE), - ), - text: "(BETA) Suggestive Mode Enabled", - }).value; - const node = findDiscourseNode({ uid, title }); const isDiscourseNode = node && node.backedBy !== "default"; if (isDiscourseNode) { renderDiscourseContext({ h1, uid }); - if ( - isSuggestiveModeEnabled && - getFeatureFlag("Duplicate node alert enabled") - ) { + if (getFeatureFlag("Duplicate node alert enabled")) { renderPossibleDuplicates(h1, title, node); } const linkedReferencesDiv = document.querySelector( @@ -207,7 +197,7 @@ export const initObservers = async ({ }); }) as EventListener; - if (onloadArgs.extensionAPI.settings.get("suggestive-mode-overlay")) { + if (getFeatureFlag("Suggestive mode overlay enabled")) { addPageRefObserver(getSuggestiveOverlayHandler(onloadArgs)); }