Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 69 additions & 18 deletions apps/roam/src/components/settings/utils/accessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import internalError from "~/utils/internalError";
import { getSetting } from "~/utils/extensionSettings";
import { getFormattedConfigTree } from "~/utils/discourseConfigRef";
import { roamNodeToCondition } from "~/utils/parseQuery";
import type { DiscourseRelation } from "~/utils/getDiscourseRelations";
import type { DiscourseNode } from "~/utils/getDiscourseNodes";
import type { Condition } from "~/utils/types";
import { z } from "zod";

import {
Expand All @@ -27,7 +30,7 @@ import {
type GlobalSettings,
type PersonalSettings,
type DiscourseNodeSettings,
type DiscourseRelationSettings,
type Condition as SchemaCondition,
} from "./zodSchema";

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

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

export const getAllRelations = (): DiscourseRelationSettings[] => {
export const getAllRelations = (): DiscourseRelation[] => {
const settings = getGlobalSettings();

return Object.entries(settings.Relations).map(([id, relation]) => ({
...relation,
id,
}));
return Object.entries(settings.Relations).flatMap(([id, relation]) =>
relation.ifConditions.map((ifCondition) => ({
id,
label: relation.label,
source: relation.source,
destination: relation.destination,
complement: relation.complement,
triples: ifCondition.triples,
})),
);
};

export const getPersonalSettings = (): PersonalSettings => {
Expand Down Expand Up @@ -936,7 +940,52 @@ export const setDiscourseNodeSetting = (
setBlockPropAtPath(pageUid, keys, value);
};

export const getAllDiscourseNodes = (): DiscourseNodeSettings[] => {
const addConditionUids = (conditions: SchemaCondition[]): Condition[] =>
conditions.map((c) => {
const uid = window.roamAlphaAPI.util.generateUID();
if (c.type === "or" || c.type === "not or") {
return {
uid,
type: c.type,
conditions: c.conditions.map(addConditionUids),
};
}
return {
uid,
type: c.type,
source: c.source,
relation: c.relation,
target: c.target,
not: c.not,
};
}) as Condition[];

const toDiscourseNode = (settings: DiscourseNodeSettings): DiscourseNode => ({
text: settings.text,
type: settings.type,
shortcut: settings.shortcut,
tag: settings.tag || undefined,
format: settings.format,
description: settings.description || undefined,
graphOverview: settings.graphOverview || undefined,
backedBy: "user",
specification: addConditionUids(
settings.specification.query.conditions as SchemaCondition[],
),
canvasSettings: Object.fromEntries(
Object.entries(settings.canvasSettings).map(([k, v]) => [
k,
typeof v === "boolean" ? (v ? "true" : "") : String(v),
]),
),
template: settings.template.length > 0 ? settings.template : undefined,
embeddingRef: settings.suggestiveRules.embeddingRef || undefined,
isFirstChild: settings.suggestiveRules.isFirstChild
? { uid: "", value: true }
: undefined,
});
Comment thread
sid597 marked this conversation as resolved.

export const getAllDiscourseNodes = (): DiscourseNode[] => {
const results = window.roamAlphaAPI.data.fast.q(`
[:find ?uid ?title (pull ?page [:block/props])
:where
Expand All @@ -945,7 +994,7 @@ export const getAllDiscourseNodes = (): DiscourseNodeSettings[] => {
[(clojure.string/starts-with? ?title "${DISCOURSE_NODE_PAGE_PREFIX}")]]
`) as [string, string, Record<string, json> | null][];

const nodes: DiscourseNodeSettings[] = [];
const nodes: DiscourseNode[] = [];

for (const [pageUid, title, rawProps] of results) {
if (typeof pageUid !== "string" || typeof title !== "string") continue;
Expand All @@ -962,11 +1011,13 @@ export const getAllDiscourseNodes = (): DiscourseNodeSettings[] => {

const result = DiscourseNodeSchema.safeParse(blockProps);
if (result.success) {
nodes.push({
...result.data,
type: pageUid,
text: title.replace(DISCOURSE_NODE_PAGE_PREFIX, ""),
});
nodes.push(
toDiscourseNode({
...result.data,
type: pageUid,
text: title.replace(DISCOURSE_NODE_PAGE_PREFIX, ""),
}),
);
} else {
internalError({
error: result.error,
Expand Down
2 changes: 1 addition & 1 deletion apps/roam/src/components/settings/utils/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ const initSingleDiscourseNode = async (
tag: node.tag || "",
graphOverview: node.graphOverview ?? false,
canvasSettings: node.canvasSettings || {},
backedBy: "default",
backedBy: "user",
});

setBlockProps(pageUid, nodeData, false);
Expand Down
2 changes: 1 addition & 1 deletion apps/roam/src/components/settings/utils/zodSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const QBClauseDataSchema = z.object({
not: z.boolean().optional(),
});

type Condition =
export type Condition =
| (z.infer<typeof QBClauseDataSchema> & { type: "clause" })
| (z.infer<typeof QBClauseDataSchema> & { type: "not" })
| { type: "or"; conditions: Condition[][] }
Expand Down
143 changes: 79 additions & 64 deletions apps/roam/src/utils/getDiscourseNodes.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromTree";
import getSubTree from "roamjs-components/util/getSubTree";
import {
isNewSettingsStoreEnabled,
getAllDiscourseNodes,
} from "~/components/settings/utils/accessors";
import discourseConfigRef from "./discourseConfigRef";
import getDiscourseRelations from "./getDiscourseRelations";
import { roamNodeToCondition } from "./parseQuery";
Expand Down Expand Up @@ -103,72 +107,83 @@ const getUidAndBooleanSetting = ({
};

const getDiscourseNodes = (relations = getDiscourseRelations()) => {
const configuredNodes = Object.entries(discourseConfigRef.nodes)
.map(([type, { text, children }]): DiscourseNode => {
const suggestiveRules = getSubTree({
tree: children,
key: "Suggestive Rules",
});
const embeddingBlockRef = getSubTree({
tree: suggestiveRules.children,
key: "Embedding Block Ref",
});
const configuredNodes = (
isNewSettingsStoreEnabled()
? getAllDiscourseNodes()
: Object.entries(discourseConfigRef.nodes).map(
([type, { text, children }]): DiscourseNode => {
const suggestiveRules = getSubTree({
tree: children,
key: "Suggestive Rules",
});
const embeddingBlockRef = getSubTree({
tree: suggestiveRules.children,
key: "Embedding Block Ref",
});

return {
format: getSettingValueFromTree({ tree: children, key: "format" }),
text,
shortcut: getSettingValueFromTree({ tree: children, key: "shortcut" }),
tag: getSettingValueFromTree({ tree: children, key: "tag" }),
type,
specification: getSpecification(children),
backedBy: "user",
canvasSettings: Object.fromEntries(
getSubTree({ tree: children, key: "canvas" }).children.map(
(c) => [c.text, c.children[0]?.text || ""] as const,
),
),
graphOverview:
children.filter((c) => c.text === "Graph Overview").length > 0,
description: getSettingValueFromTree({
tree: children,
key: "description",
}),
template: getSubTree({ tree: children, key: "template" }).children,
embeddingRef: embeddingBlockRef?.children?.[0]?.text,
embeddingRefUid: embeddingBlockRef?.uid,
isFirstChild: getUidAndBooleanSetting({
tree: suggestiveRules.children,
text: "First Child",
}),
};
})
.concat(
relations
.filter((r) => r.triples.some((t) => t.some((n) => /anchor/i.test(n))))
.map((r) => ({
format: "",
text: r.label,
type: r.id,
shortcut: r.label.slice(0, 1),
tag: "",
specification: r.triples.map(([source, relation, target]) => ({
type: "clause",
source: /anchor/i.test(source) ? r.label : source,
relation,
target:
target === "source"
? r.source
: target === "destination"
? r.destination
: /anchor/i.test(target)
? r.label
: target,
uid: window.roamAlphaAPI.util.generateUID(),
})),
backedBy: "relation",
canvasSettings: {},
return {
format: getSettingValueFromTree({
tree: children,
key: "format",
}),
text,
shortcut: getSettingValueFromTree({
tree: children,
key: "shortcut",
}),
tag: getSettingValueFromTree({ tree: children, key: "tag" }),
type,
specification: getSpecification(children),
backedBy: "user",
canvasSettings: Object.fromEntries(
getSubTree({ tree: children, key: "canvas" }).children.map(
(c) => [c.text, c.children[0]?.text || ""] as const,
),
),
graphOverview:
children.filter((c) => c.text === "Graph Overview").length > 0,
description: getSettingValueFromTree({
tree: children,
key: "description",
}),
template: getSubTree({ tree: children, key: "template" })
.children,
embeddingRef: embeddingBlockRef?.children?.[0]?.text,
embeddingRefUid: embeddingBlockRef?.uid,
isFirstChild: getUidAndBooleanSetting({
tree: suggestiveRules.children,
text: "First Child",
}),
};
},
)
).concat(
relations
.filter((r) => r.triples.some((t) => t.some((n) => /anchor/i.test(n))))
.map((r) => ({
format: "",
text: r.label,
type: r.id,
shortcut: r.label.slice(0, 1),
tag: "",
specification: r.triples.map(([source, relation, target]) => ({
type: "clause",
source: /anchor/i.test(source) ? r.label : source,
relation,
target:
target === "source"
? r.source
: target === "destination"
? r.destination
: /anchor/i.test(target)
? r.label
: target,
uid: window.roamAlphaAPI.util.generateUID(),
})),
);
backedBy: "relation",
canvasSettings: {},
})),
);
const configuredNodeTexts = new Set(configuredNodes.map((n) => n.text));
const defaultNodes = DEFAULT_NODES.filter(
(n) => !configuredNodeTexts.has(n.text),
Expand Down
8 changes: 8 additions & 0 deletions apps/roam/src/utils/getDiscourseRelations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import type {
import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromTree";
import toFlexRegex from "roamjs-components/util/toFlexRegex";
import DEFAULT_RELATION_VALUES from "~/data/defaultDiscourseRelations";
import {
isNewSettingsStoreEnabled,
getAllRelations,
} from "~/components/settings/utils/accessors";
import discourseConfigRef from "./discourseConfigRef";

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

const getDiscourseRelations = () => {
if (isNewSettingsStoreEnabled()) {
return getAllRelations();
}

const grammarNode = getGrammarNode();
const relationsNode = getRelationsNode(grammarNode);
const relationNodes = relationsNode?.children || DEFAULT_RELATION_VALUES;
Expand Down