Skip to content

Commit e2bcc28

Browse files
committed
ENG-1291: Port discourse node specification
1 parent ff23661 commit e2bcc28

6 files changed

Lines changed: 88 additions & 54 deletions

File tree

apps/roam/src/components/QueryBuilder.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ type QueryPageComponent = (props: {
3232
isEditBlock?: boolean;
3333
showAlias?: boolean;
3434
discourseNodeType?: string;
35+
settingKey?: "index" | "specification";
3536
}) => JSX.Element;
3637

3738
type Props = Parameters<QueryPageComponent>[0];
@@ -41,6 +42,7 @@ const QueryBuilder = ({
4142
isEditBlock,
4243
showAlias,
4344
discourseNodeType,
45+
settingKey,
4446
}: Props) => {
4547
const extensionAPI = useExtensionAPI();
4648
const hideMetadata = useMemo(
@@ -165,6 +167,7 @@ const QueryBuilder = ({
165167
<QueryEditor
166168
parentUid={pageUid}
167169
discourseNodeType={discourseNodeType}
170+
settingKey={settingKey}
168171
onQuery={() => {
169172
setHasResults(true);
170173
setIsEdit(false);

apps/roam/src/components/QueryEditor.tsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,7 @@ type QueryEditorComponent = (props: {
437437
hideCustomSwitch?: boolean;
438438
showAlias?: boolean;
439439
discourseNodeType?: string;
440+
settingKey?: "index" | "specification";
440441
}) => JSX.Element;
441442

442443
const QueryEditor: QueryEditorComponent = ({
@@ -446,6 +447,7 @@ const QueryEditor: QueryEditorComponent = ({
446447
hideCustomSwitch,
447448
showAlias,
448449
discourseNodeType,
450+
settingKey,
449451
}) => {
450452
useEffect(() => {
451453
const previewQuery = ((e: CustomEvent) => {
@@ -487,7 +489,7 @@ const QueryEditor: QueryEditorComponent = ({
487489
return () => window.clearTimeout(blockPropSyncTimeoutRef.current);
488490
}, []);
489491
useEffect(() => {
490-
if (!discourseNodeType) return;
492+
if (!discourseNodeType || !settingKey) return;
491493

492494
const stripped: unknown = JSON.parse(
493495
JSON.stringify(
@@ -501,18 +503,20 @@ const QueryEditor: QueryEditorComponent = ({
501503

502504
const result = IndexSchema.safeParse(stripped);
503505
if (!result.success) {
504-
console.error("Index blockprop sync failed validation:", result.error);
506+
console.error(`${settingKey} blockprop sync failed validation:`, result.error);
505507
return;
506508
}
507509

510+
const path = settingKey === "index" ? ["index"] : ["specification", "query"];
511+
508512
window.clearTimeout(blockPropSyncTimeoutRef.current);
509513
blockPropSyncTimeoutRef.current = window.setTimeout(() => {
510-
setDiscourseNodeSetting(discourseNodeType, ["index"], result.data);
514+
setDiscourseNodeSetting(discourseNodeType, path, result.data);
511515
lastSyncedIndexRef.current = serialized;
512516
}, 250);
513517

514518
return () => window.clearTimeout(blockPropSyncTimeoutRef.current);
515-
}, [conditions, selections, custom, discourseNodeType]);
519+
}, [conditions, selections, custom, discourseNodeType, settingKey]);
516520

517521
const customNodeOnChange = (value: string) => {
518522
window.clearTimeout(debounceRef.current);

apps/roam/src/components/settings/DiscourseNodeIndex.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ const NodeIndex = ({
6060
},
6161
],
6262
selections: [],
63+
custom: "",
64+
returnNode: DEFAULT_RETURN_NODE,
6365
});
6466

6567
setShowQuery(true);
@@ -69,7 +71,7 @@ const NodeIndex = ({
6971
return (
7072
<ExtensionApiContextProvider {...onloadArgs}>
7173
{showQuery ? (
72-
<QueryBuilder pageUid={parentUid} discourseNodeType={node.type} />
74+
<QueryBuilder pageUid={parentUid} discourseNodeType={node.type} settingKey="index" />
7375
) : (
7476
<Spinner />
7577
)}

apps/roam/src/components/settings/DiscourseNodeSpecification.tsx

Lines changed: 52 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import React from "react";
22
import getSubTree from "roamjs-components/util/getSubTree";
33
import createBlock from "roamjs-components/writes/createBlock";
4-
import { Checkbox } from "@blueprintjs/core";
54
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
65
import deleteBlock from "roamjs-components/writes/deleteBlock";
76
import refreshConfigTree from "~/utils/refreshConfigTree";
87
import getDiscourseNodes from "~/utils/getDiscourseNodes";
98
import getDiscourseNodeFormatExpression from "~/utils/getDiscourseNodeFormatExpression";
109
import QueryEditor from "~/components/QueryEditor";
1110
import internalError from "~/utils/internalError";
11+
import { setDiscourseNodeSetting } from "~/components/settings/utils/accessors";
12+
import { DiscourseNodeFlagPanel } from "~/components/settings/components/BlockPropSettingPanels";
1213

1314
const NodeSpecification = ({
1415
parentUid,
@@ -20,11 +21,14 @@ const NodeSpecification = ({
2021
parentSetEnabled?: (enabled: boolean) => void;
2122
}) => {
2223
const [migrated, setMigrated] = React.useState(false);
23-
const [enabled, setEnabled] = React.useState<string>(
24+
const enabledBlockUid = React.useMemo(
2425
() =>
2526
getSubTree({ tree: getBasicTreeByParentUid(parentUid), key: "enabled" })
2627
?.uid,
28+
[parentUid],
2729
);
30+
const [enabled, setEnabled] = React.useState(!!enabledBlockUid);
31+
2832
React.useEffect(() => {
2933
if (enabled) {
3034
const scratchNode = getSubTree({ parentUid, key: "scratch" });
@@ -69,19 +73,41 @@ const NodeSpecification = ({
6973
},
7074
}),
7175
)
72-
.then(() => setMigrated(true))
76+
.then(() => {
77+
setDiscourseNodeSetting(node.type, ["specification", "query"], {
78+
conditions: [
79+
{
80+
type: "clause" as const,
81+
source: node.text,
82+
relation: "has title",
83+
target: `/${getDiscourseNodeFormatExpression(node.format).source}/`,
84+
},
85+
],
86+
selections: [],
87+
custom: "",
88+
returnNode: node.text,
89+
});
90+
setMigrated(true);
91+
})
7392
.catch((error) => {
7493
internalError({ error });
7594
});
7695
}
7796
} else {
7897
const tree = getBasicTreeByParentUid(parentUid);
7998
const scratchNode = getSubTree({ tree, key: "scratch" });
80-
Promise.all(scratchNode.children.map((c) => deleteBlock(c.uid))).catch(
81-
(error) => {
99+
Promise.all(scratchNode.children.map((c) => deleteBlock(c.uid)))
100+
.then(() => {
101+
setDiscourseNodeSetting(node.type, ["specification", "query"], {
102+
conditions: [],
103+
selections: [],
104+
custom: "",
105+
returnNode: "",
106+
});
107+
})
108+
.catch((error) => {
82109
internalError({ error });
83-
},
84-
);
110+
});
85111
}
86112
return () => {
87113
refreshConfigTree();
@@ -90,47 +116,33 @@ const NodeSpecification = ({
90116
return (
91117
<div className={"roamjs-node-specification"}>
92118
<style>
93-
{`.roamjs-node-specification .bp3-button.bp3-intent-primary { display: none; }`}
119+
{`.roamjs-node-specification .bp3-button.bp3-intent-primary { display: none; }
120+
.roamjs-node-specification .bp3-checkbox { visibility: hidden; }
121+
.roamjs-node-specification .bp3-checkbox .bp3-control-indicator { visibility: visible; }`}
94122
</style>
95-
<p>
96-
<Checkbox
97-
checked={!!enabled}
98-
className={"ml-8 inline-block"}
99-
onChange={(e) => {
100-
const flag = (e.target as HTMLInputElement).checked;
101-
if (flag) {
102-
createBlock({
103-
parentUid,
104-
order: 2,
105-
node: { text: "enabled" },
106-
})
107-
.then((uid: string) => {
108-
setEnabled(uid);
109-
if (parentSetEnabled) parentSetEnabled(true);
110-
})
111-
.catch((error) => {
112-
internalError({ error });
113-
});
114-
} else {
115-
deleteBlock(enabled)
116-
.then(() => {
117-
setEnabled("");
118-
if (parentSetEnabled) parentSetEnabled(false);
119-
})
120-
.catch((error) => {
121-
internalError({ error });
122-
});
123-
}
124-
}}
125-
/>
126-
</p>
123+
<DiscourseNodeFlagPanel
124+
nodeType={node.type}
125+
title="enabled"
126+
description=""
127+
settingKeys={["specification", "enabled"]}
128+
defaultValue={enabled}
129+
parentUid={parentUid}
130+
uid={enabledBlockUid}
131+
order={2}
132+
onChange={(checked) => {
133+
setEnabled(checked);
134+
parentSetEnabled?.(checked);
135+
}}
136+
/>
127137
<div
128138
className={`${enabled ? "" : "bg-gray-200 opacity-75"} overflow-auto`}
129139
>
130140
<QueryEditor
131141
parentUid={parentUid}
132142
key={Number(migrated)}
133143
hideCustomSwitch
144+
discourseNodeType={node.type}
145+
settingKey="specification"
134146
/>
135147
</div>
136148
</div>

apps/roam/src/components/settings/utils/zodSchema.example.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,22 @@ const discourseNodeSettings: DiscourseNodeSettings = {
4545
shortcut: "C",
4646
tag: "#claim",
4747
description: "A statement or assertion that can be supported or refuted",
48-
specification: [
49-
{
50-
type: "clause",
51-
source: "Claim",
52-
relation: "has title",
53-
target: "/^\\[\\[CLM\\]\\]/",
48+
specification: {
49+
enabled: true,
50+
query: {
51+
conditions: [
52+
{
53+
type: "clause",
54+
source: "Claim",
55+
relation: "has title",
56+
target: "/^\\[\\[CLM\\]\\]/",
57+
},
58+
],
59+
selections: [],
60+
custom: "",
61+
returnNode: "Claim",
5462
},
55-
],
63+
},
5664
template: [
5765
{ text: "Summary::", heading: 2 },
5866
{ text: "Evidence::", heading: 2, children: [{ text: "" }] },
@@ -76,6 +84,7 @@ const discourseNodeSettings: DiscourseNodeSettings = {
7684
],
7785
selections: [],
7886
custom: "",
87+
returnNode: "node",
7988
},
8089
suggestiveRules,
8190
backedBy: "user",

apps/roam/src/components/settings/utils/zodSchema.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export const IndexSchema = z.object({
5353
conditions: z.array(ConditionSchema).default([]),
5454
selections: z.array(SelectionSchema).default([]),
5555
custom: z.string().default(""),
56+
returnNode: z.string().default(""),
5657
});
5758

5859
type RoamNode = {
@@ -103,10 +104,13 @@ export const DiscourseNodeSchema = z.object({
103104
tag: stringWithDefault(""),
104105
description: stringWithDefault(""),
105106
specification: z
106-
.array(ConditionSchema)
107+
.object({
108+
enabled: z.boolean().default(false),
109+
query: IndexSchema.default({}),
110+
})
107111
.nullable()
108112
.optional()
109-
.transform((val) => val ?? []),
113+
.transform((val) => val ?? { enabled: false, query: { conditions: [], selections: [], custom: "", returnNode: "" } }),
110114
template: z
111115
.array(RoamNodeSchema)
112116
.nullable()

0 commit comments

Comments
 (0)