diff --git a/apps/roam/src/components/QueryBuilder.tsx b/apps/roam/src/components/QueryBuilder.tsx index 85225f526..20b5cbf47 100644 --- a/apps/roam/src/components/QueryBuilder.tsx +++ b/apps/roam/src/components/QueryBuilder.tsx @@ -31,11 +31,17 @@ type QueryPageComponent = (props: { pageUid: string; isEditBlock?: boolean; showAlias?: boolean; + discourseNodeType?: string; }) => JSX.Element; type Props = Parameters[0]; -const QueryBuilder = ({ pageUid, isEditBlock, showAlias }: Props) => { +const QueryBuilder = ({ + pageUid, + isEditBlock, + showAlias, + discourseNodeType, +}: Props) => { const extensionAPI = useExtensionAPI(); const hideMetadata = useMemo( () => @@ -158,6 +164,7 @@ const QueryBuilder = ({ pageUid, isEditBlock, showAlias }: Props) => { <> { setHasResults(true); setIsEdit(false); diff --git a/apps/roam/src/components/QueryEditor.tsx b/apps/roam/src/components/QueryEditor.tsx index 96900c7bc..a47a3198d 100644 --- a/apps/roam/src/components/QueryEditor.tsx +++ b/apps/roam/src/components/QueryEditor.tsx @@ -44,6 +44,8 @@ import { import getShallowTreeByParentUid from "roamjs-components/queries/getShallowTreeByParentUid"; import { ALL_SELECTION_SUGGESTIONS } from "~/utils/predefinedSelections"; import { getAlias } from "~/utils/parseResultSettings"; +import { setDiscourseNodeSetting } from "~/components/settings/utils/accessors"; +import { IndexSchema } from "~/components/settings/utils/zodSchema"; const getSourceCandidates = (cs: Condition[]): string[] => cs.flatMap((c) => @@ -434,6 +436,7 @@ type QueryEditorComponent = (props: { setHasResults?: () => void; hideCustomSwitch?: boolean; showAlias?: boolean; + discourseNodeType?: string; }) => JSX.Element; const QueryEditor: QueryEditorComponent = ({ @@ -442,6 +445,7 @@ const QueryEditor: QueryEditorComponent = ({ setHasResults, hideCustomSwitch, showAlias, + discourseNodeType, }) => { useEffect(() => { const previewQuery = ((e: CustomEvent) => { @@ -476,6 +480,39 @@ const QueryEditor: QueryEditorComponent = ({ const [conditions, _setConditions] = useState(initialConditions); const [selections, setSelections] = useState(initialSelections); const [custom, setCustom] = useState(initialCustom); + + const blockPropSyncTimeoutRef = useRef(0); + const lastSyncedIndexRef = useRef(""); + useEffect(() => { + return () => window.clearTimeout(blockPropSyncTimeoutRef.current); + }, []); + useEffect(() => { + if (!discourseNodeType) return; + + const stripped: unknown = JSON.parse( + JSON.stringify({ conditions, selections, custom }, (key, value: unknown) => + key === "uid" ? undefined : value, + ), + ); + + const serialized = JSON.stringify(stripped); + if (serialized === lastSyncedIndexRef.current) return; + + const result = IndexSchema.safeParse(stripped); + if (!result.success) { + console.error("Index blockprop sync failed validation:", result.error); + return; + } + + window.clearTimeout(blockPropSyncTimeoutRef.current); + blockPropSyncTimeoutRef.current = window.setTimeout(() => { + setDiscourseNodeSetting(discourseNodeType, ["index"], result.data); + lastSyncedIndexRef.current = serialized; + }, 250); + + return () => window.clearTimeout(blockPropSyncTimeoutRef.current); + }, [conditions, selections, custom, discourseNodeType]); + const customNodeOnChange = (value: string) => { window.clearTimeout(debounceRef.current); setCustom(value); diff --git a/apps/roam/src/components/settings/DiscourseNodeIndex.tsx b/apps/roam/src/components/settings/DiscourseNodeIndex.tsx index 709a0fc00..ad1b0a40e 100644 --- a/apps/roam/src/components/settings/DiscourseNodeIndex.tsx +++ b/apps/roam/src/components/settings/DiscourseNodeIndex.tsx @@ -6,6 +6,7 @@ import type { DiscourseNode } from "~/utils/getDiscourseNodes"; import QueryBuilder from "~/components/QueryBuilder"; import parseQuery, { DEFAULT_RETURN_NODE } from "~/utils/parseQuery"; import createBlock from "roamjs-components/writes/createBlock"; +import { setDiscourseNodeSetting } from "~/components/settings/utils/accessors"; const NodeIndex = ({ parentUid, @@ -25,7 +26,7 @@ const NodeIndex = ({ ); useEffect(() => { if (!showQuery) { - createBlock({ + void createBlock({ parentUid: initialQueryArgs.conditionsNodesUid, node: { text: "clause", @@ -48,12 +49,30 @@ const NodeIndex = ({ }, ], }, - }).then(() => setShowQuery(true)); + }).then(() => { + setDiscourseNodeSetting(node.type, ["index"], { + conditions: [ + { + type: "clause", + source: DEFAULT_RETURN_NODE, + relation: "is a", + target: node.text, + }, + ], + selections: [], + }); + + setShowQuery(true); + }); } - }, [parentUid, initialQueryArgs, showQuery]); + }, [parentUid, initialQueryArgs, showQuery, node.text, node.type]); return ( - {showQuery ? : } + {showQuery ? ( + + ) : ( + + )} ); }; diff --git a/apps/roam/src/components/settings/utils/zodSchema.example.ts b/apps/roam/src/components/settings/utils/zodSchema.example.ts index ee9187912..d72b6b7c0 100644 --- a/apps/roam/src/components/settings/utils/zodSchema.example.ts +++ b/apps/roam/src/components/settings/utils/zodSchema.example.ts @@ -75,6 +75,7 @@ const discourseNodeSettings: DiscourseNodeSettings = { }, ], selections: [], + custom: "", }, suggestiveRules, backedBy: "user", diff --git a/apps/roam/src/components/settings/utils/zodSchema.ts b/apps/roam/src/components/settings/utils/zodSchema.ts index 3c354f8df..5e49a1bc3 100644 --- a/apps/roam/src/components/settings/utils/zodSchema.ts +++ b/apps/roam/src/components/settings/utils/zodSchema.ts @@ -52,6 +52,7 @@ export const SelectionSchema = z.object({ export const IndexSchema = z.object({ conditions: z.array(ConditionSchema).default([]), selections: z.array(SelectionSchema).default([]), + custom: z.string().default(""), }); type RoamNode = {