Skip to content

Commit 6606ffa

Browse files
authored
Merge pull request #853 from DiscourseGraphs/eng-1469-refactor-getdiscourserelations-and-getdiscoursenodes-to-read
ENG-1469: Refactor getDiscourseRelations and getDiscourseNodes to read from block props
2 parents 46fa9bc + 915c0eb commit 6606ffa

5 files changed

Lines changed: 158 additions & 84 deletions

File tree

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

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import internalError from "~/utils/internalError";
1212
import { getSetting } from "~/utils/extensionSettings";
1313
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
1414
import { roamNodeToCondition } from "~/utils/parseQuery";
15+
import type { DiscourseRelation } from "~/utils/getDiscourseRelations";
16+
import type { DiscourseNode } from "~/utils/getDiscourseNodes";
17+
import type { Condition } from "~/utils/types";
1518
import { z } from "zod";
1619

1720
import {
@@ -27,7 +30,7 @@ import {
2730
type GlobalSettings,
2831
type PersonalSettings,
2932
type DiscourseNodeSettings,
30-
type DiscourseRelationSettings,
33+
type Condition as SchemaCondition,
3134
} from "./zodSchema";
3235

3336
const isRecord = (value: unknown): value is Record<string, unknown> =>
@@ -250,11 +253,6 @@ const getLegacyPersonalSetting = (keys: string[]): unknown => {
250253
return undefined;
251254
};
252255

253-
// NOTE(ENG-1469): This returns the block props schema shape (Record<uid, {label, source,
254-
// destination, complement, ifConditions}>). Runtime consumers use getDiscourseRelations()
255-
// which returns a flat DiscourseRelation[] with a different structure (one entry per
256-
// if-block, triples at top level, no nodePositions). When migrating getDiscourseRelations()
257-
// to read from block props, it will need a conversion from this shape to the flat array.
258256
const getLegacyRelationsSetting = (): Record<string, unknown> => {
259257
const settingsUid = getPageUidByPageTitle(DG_BLOCK_PROP_SETTINGS_PAGE_TITLE);
260258
if (!settingsUid) return DEFAULT_GLOBAL_SETTINGS.Relations;
@@ -768,13 +766,19 @@ export const setGlobalSetting = (keys: string[], value: json): void => {
768766
});
769767
};
770768

771-
export const getAllRelations = (): DiscourseRelationSettings[] => {
769+
export const getAllRelations = (): DiscourseRelation[] => {
772770
const settings = getGlobalSettings();
773771

774-
return Object.entries(settings.Relations).map(([id, relation]) => ({
775-
...relation,
776-
id,
777-
}));
772+
return Object.entries(settings.Relations).flatMap(([id, relation]) =>
773+
relation.ifConditions.map((ifCondition) => ({
774+
id,
775+
label: relation.label,
776+
source: relation.source,
777+
destination: relation.destination,
778+
complement: relation.complement,
779+
triples: ifCondition.triples,
780+
})),
781+
);
778782
};
779783

780784
export const getPersonalSettings = (): PersonalSettings => {
@@ -940,7 +944,52 @@ export const setDiscourseNodeSetting = (
940944
setBlockPropAtPath(pageUid, keys, value);
941945
};
942946

943-
export const getAllDiscourseNodes = (): DiscourseNodeSettings[] => {
947+
const addConditionUids = (conditions: SchemaCondition[]): Condition[] =>
948+
conditions.map((c) => {
949+
const uid = window.roamAlphaAPI.util.generateUID();
950+
if (c.type === "or" || c.type === "not or") {
951+
return {
952+
uid,
953+
type: c.type,
954+
conditions: c.conditions.map(addConditionUids),
955+
};
956+
}
957+
return {
958+
uid,
959+
type: c.type,
960+
source: c.source,
961+
relation: c.relation,
962+
target: c.target,
963+
not: c.not,
964+
};
965+
}) as Condition[];
966+
967+
const toDiscourseNode = (settings: DiscourseNodeSettings): DiscourseNode => ({
968+
text: settings.text,
969+
type: settings.type,
970+
shortcut: settings.shortcut,
971+
tag: settings.tag || undefined,
972+
format: settings.format,
973+
description: settings.description || undefined,
974+
graphOverview: settings.graphOverview || undefined,
975+
backedBy: "user",
976+
specification: addConditionUids(
977+
settings.specification.query.conditions as SchemaCondition[],
978+
),
979+
canvasSettings: Object.fromEntries(
980+
Object.entries(settings.canvasSettings).map(([k, v]) => [
981+
k,
982+
typeof v === "boolean" ? (v ? "true" : "") : String(v),
983+
]),
984+
),
985+
template: settings.template.length > 0 ? settings.template : undefined,
986+
embeddingRef: settings.suggestiveRules.embeddingRef || undefined,
987+
isFirstChild: settings.suggestiveRules.isFirstChild
988+
? { uid: "", value: true }
989+
: undefined,
990+
});
991+
992+
export const getAllDiscourseNodes = (): DiscourseNode[] => {
944993
const results = window.roamAlphaAPI.data.fast.q(`
945994
[:find ?uid ?title (pull ?page [:block/props])
946995
:where
@@ -949,7 +998,7 @@ export const getAllDiscourseNodes = (): DiscourseNodeSettings[] => {
949998
[(clojure.string/starts-with? ?title "${DISCOURSE_NODE_PAGE_PREFIX}")]]
950999
`) as [string, string, Record<string, json> | null][];
9511000

952-
const nodes: DiscourseNodeSettings[] = [];
1001+
const nodes: DiscourseNode[] = [];
9531002

9541003
for (const [pageUid, title, rawProps] of results) {
9551004
if (typeof pageUid !== "string" || typeof title !== "string") continue;
@@ -966,11 +1015,13 @@ export const getAllDiscourseNodes = (): DiscourseNodeSettings[] => {
9661015

9671016
const result = DiscourseNodeSchema.safeParse(blockProps);
9681017
if (result.success) {
969-
nodes.push({
970-
...result.data,
971-
type: pageUid,
972-
text: title.replace(DISCOURSE_NODE_PAGE_PREFIX, ""),
973-
});
1018+
nodes.push(
1019+
toDiscourseNode({
1020+
...result.data,
1021+
type: pageUid,
1022+
text: title.replace(DISCOURSE_NODE_PAGE_PREFIX, ""),
1023+
}),
1024+
);
9741025
} else {
9751026
internalError({
9761027
error: result.error,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ const initSingleDiscourseNode = async (
147147
tag: node.tag || "",
148148
graphOverview: node.graphOverview ?? false,
149149
canvasSettings: node.canvasSettings || {},
150-
backedBy: "default",
150+
backedBy: "user",
151151
});
152152

153153
setBlockProps(pageUid, nodeData, false);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ const QBClauseDataSchema = z.object({
2222
not: z.boolean().optional(),
2323
});
2424

25-
type Condition =
25+
export type Condition =
2626
| (z.infer<typeof QBClauseDataSchema> & { type: "clause" })
2727
| (z.infer<typeof QBClauseDataSchema> & { type: "not" })
2828
| { type: "or"; conditions: Condition[][] }

apps/roam/src/utils/getDiscourseNodes.ts

Lines changed: 79 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromTree";
22
import getSubTree from "roamjs-components/util/getSubTree";
3+
import {
4+
isNewSettingsStoreEnabled,
5+
getAllDiscourseNodes,
6+
} from "~/components/settings/utils/accessors";
37
import discourseConfigRef from "./discourseConfigRef";
48
import getDiscourseRelations from "./getDiscourseRelations";
59
import { roamNodeToCondition } from "./parseQuery";
@@ -103,72 +107,83 @@ const getUidAndBooleanSetting = ({
103107
};
104108

105109
const getDiscourseNodes = (relations = getDiscourseRelations()) => {
106-
const configuredNodes = Object.entries(discourseConfigRef.nodes)
107-
.map(([type, { text, children }]): DiscourseNode => {
108-
const suggestiveRules = getSubTree({
109-
tree: children,
110-
key: "Suggestive Rules",
111-
});
112-
const embeddingBlockRef = getSubTree({
113-
tree: suggestiveRules.children,
114-
key: "Embedding Block Ref",
115-
});
110+
const configuredNodes = (
111+
isNewSettingsStoreEnabled()
112+
? getAllDiscourseNodes()
113+
: Object.entries(discourseConfigRef.nodes).map(
114+
([type, { text, children }]): DiscourseNode => {
115+
const suggestiveRules = getSubTree({
116+
tree: children,
117+
key: "Suggestive Rules",
118+
});
119+
const embeddingBlockRef = getSubTree({
120+
tree: suggestiveRules.children,
121+
key: "Embedding Block Ref",
122+
});
116123

117-
return {
118-
format: getSettingValueFromTree({ tree: children, key: "format" }),
119-
text,
120-
shortcut: getSettingValueFromTree({ tree: children, key: "shortcut" }),
121-
tag: getSettingValueFromTree({ tree: children, key: "tag" }),
122-
type,
123-
specification: getSpecification(children),
124-
backedBy: "user",
125-
canvasSettings: Object.fromEntries(
126-
getSubTree({ tree: children, key: "canvas" }).children.map(
127-
(c) => [c.text, c.children[0]?.text || ""] as const,
128-
),
129-
),
130-
graphOverview:
131-
children.filter((c) => c.text === "Graph Overview").length > 0,
132-
description: getSettingValueFromTree({
133-
tree: children,
134-
key: "description",
135-
}),
136-
template: getSubTree({ tree: children, key: "template" }).children,
137-
embeddingRef: embeddingBlockRef?.children?.[0]?.text,
138-
embeddingRefUid: embeddingBlockRef?.uid,
139-
isFirstChild: getUidAndBooleanSetting({
140-
tree: suggestiveRules.children,
141-
text: "First Child",
142-
}),
143-
};
144-
})
145-
.concat(
146-
relations
147-
.filter((r) => r.triples.some((t) => t.some((n) => /anchor/i.test(n))))
148-
.map((r) => ({
149-
format: "",
150-
text: r.label,
151-
type: r.id,
152-
shortcut: r.label.slice(0, 1),
153-
tag: "",
154-
specification: r.triples.map(([source, relation, target]) => ({
155-
type: "clause",
156-
source: /anchor/i.test(source) ? r.label : source,
157-
relation,
158-
target:
159-
target === "source"
160-
? r.source
161-
: target === "destination"
162-
? r.destination
163-
: /anchor/i.test(target)
164-
? r.label
165-
: target,
166-
uid: window.roamAlphaAPI.util.generateUID(),
167-
})),
168-
backedBy: "relation",
169-
canvasSettings: {},
124+
return {
125+
format: getSettingValueFromTree({
126+
tree: children,
127+
key: "format",
128+
}),
129+
text,
130+
shortcut: getSettingValueFromTree({
131+
tree: children,
132+
key: "shortcut",
133+
}),
134+
tag: getSettingValueFromTree({ tree: children, key: "tag" }),
135+
type,
136+
specification: getSpecification(children),
137+
backedBy: "user",
138+
canvasSettings: Object.fromEntries(
139+
getSubTree({ tree: children, key: "canvas" }).children.map(
140+
(c) => [c.text, c.children[0]?.text || ""] as const,
141+
),
142+
),
143+
graphOverview:
144+
children.filter((c) => c.text === "Graph Overview").length > 0,
145+
description: getSettingValueFromTree({
146+
tree: children,
147+
key: "description",
148+
}),
149+
template: getSubTree({ tree: children, key: "template" })
150+
.children,
151+
embeddingRef: embeddingBlockRef?.children?.[0]?.text,
152+
embeddingRefUid: embeddingBlockRef?.uid,
153+
isFirstChild: getUidAndBooleanSetting({
154+
tree: suggestiveRules.children,
155+
text: "First Child",
156+
}),
157+
};
158+
},
159+
)
160+
).concat(
161+
relations
162+
.filter((r) => r.triples.some((t) => t.some((n) => /anchor/i.test(n))))
163+
.map((r) => ({
164+
format: "",
165+
text: r.label,
166+
type: r.id,
167+
shortcut: r.label.slice(0, 1),
168+
tag: "",
169+
specification: r.triples.map(([source, relation, target]) => ({
170+
type: "clause",
171+
source: /anchor/i.test(source) ? r.label : source,
172+
relation,
173+
target:
174+
target === "source"
175+
? r.source
176+
: target === "destination"
177+
? r.destination
178+
: /anchor/i.test(target)
179+
? r.label
180+
: target,
181+
uid: window.roamAlphaAPI.util.generateUID(),
170182
})),
171-
);
183+
backedBy: "relation",
184+
canvasSettings: {},
185+
})),
186+
);
172187
const configuredNodeTexts = new Set(configuredNodes.map((n) => n.text));
173188
const defaultNodes = DEFAULT_NODES.filter(
174189
(n) => !configuredNodeTexts.has(n.text),

apps/roam/src/utils/getDiscourseRelations.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import type {
66
import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromTree";
77
import toFlexRegex from "roamjs-components/util/toFlexRegex";
88
import DEFAULT_RELATION_VALUES from "~/data/defaultDiscourseRelations";
9+
import {
10+
isNewSettingsStoreEnabled,
11+
getAllRelations,
12+
} from "~/components/settings/utils/accessors";
913
import discourseConfigRef from "./discourseConfigRef";
1014

1115
export type Triple = readonly [string, string, string];
@@ -32,6 +36,10 @@ export const getRelationsNode = (grammarNode = getGrammarNode()) => {
3236
};
3337

3438
const getDiscourseRelations = () => {
39+
if (isNewSettingsStoreEnabled()) {
40+
return getAllRelations();
41+
}
42+
3543
const grammarNode = getGrammarNode();
3644
const relationsNode = getRelationsNode(grammarNode);
3745
const relationNodes = relationsNode?.children || DEFAULT_RELATION_VALUES;

0 commit comments

Comments
 (0)