Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { DiscourseNode } from "~/utils/getDiscourseNodes";

const INITIAL_NODE_VALUES: Partial<DiscourseNode>[] = [
{
type: "_CLM-node",
format: "[[CLM]] - {content}",
text: "Claim",
shortcut: "C",
tag: "#clm-candidate",
graphOverview: true,
canvasSettings: {
color: "7DA13E",
},
},
{
type: "_QUE-node",
format: "[[QUE]] - {content}",
text: "Question",
shortcut: "Q",
graphOverview: true,
canvasSettings: {
color: "99890e",
},
},
{
type: "_EVD-node",
format: "[[EVD]] - {content} - {Source}",
text: "Evidence",
shortcut: "E",
tag: "#evd-candidate",
graphOverview: true,
canvasSettings: {
color: "DB134A",
},
},
{
type: "_SRC-node",
format: "@{content}",
text: "Source",
shortcut: "S",
graphOverview: true,
canvasSettings: {
color: "9E9E9E",
},
},
];

export default INITIAL_NODE_VALUES;
181 changes: 117 additions & 64 deletions apps/roam/src/components/settings/block-prop/utils/accessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,80 @@ import {
FeatureFlagsSchema,
GlobalSettingsSchema,
PersonalSettingsSchema,
DiscourseNodeSchema,
DiscourseNodeSettings,
} from "~/components/settings/block-prop/utils/zodSchema";
import { getPersonalSettingsKey } from "~/components/settings/block-prop/utils/init";
import {
getPersonalSettingsKey,
getDiscourseNodePageUid,
} from "~/components/settings/block-prop/utils/init";

const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value);

export const getBlockPropsByUid = (
blockUid: string,
keys: string[],
): json | undefined => {
const allBlockProps = getBlockProps(blockUid);

if (keys.length === 0) {
return allBlockProps;
}

const targetValue = keys.reduce((currentContext: json, currentKey) => {
if (
currentContext &&
typeof currentContext === "object" &&
!Array.isArray(currentContext)
) {
const value = (currentContext as Record<string, json>)[currentKey];
return value === undefined ? null : value;
}
return null;
}, allBlockProps);

return targetValue === null ? undefined : targetValue;
};

export const setBlockPropsByUid = (
blockUid: string,
keys: string[],
value: json,
): void => {
if (keys.length === 0) {
setBlockProps(blockUid, value as Record<string, json>, false);
return;
}

const currentProps = getBlockProps(blockUid);
const updatedProps = JSON.parse(JSON.stringify(currentProps || {})) as Record<
string,
json
>;

const lastKeyIndex = keys.length - 1;

keys.reduce<Record<string, json>>((currentContext, currentKey, index) => {
if (index === lastKeyIndex) {
currentContext[currentKey] = value;
return currentContext;
}

if (
!currentContext[currentKey] ||
typeof currentContext[currentKey] !== "object" ||
Array.isArray(currentContext[currentKey])
) {
currentContext[currentKey] = {};
}

return currentContext[currentKey] as Record<string, json>;
}, updatedProps);

setBlockProps(blockUid, updatedProps, false);
};

export const getBlockPropBasedSettings = ({
keys,
}: {
Expand All @@ -27,38 +95,14 @@ export const getBlockPropBasedSettings = ({
return { blockProps: undefined, blockUid: "" };
}

const sectionKey = keys[0];

const blockUid = getBlockUidByTextOnPage({
text: sectionKey,
text: keys[0],
title: DG_BLOCK_PROP_SETTINGS_PAGE_TITLE,
});

const allBlockPropsForSection = getBlockProps(blockUid);

if (keys.length > 1) {
const propertyPath = keys.slice(1);

const targetValue = propertyPath.reduce(
(currentContext: json, currentKey) => {
if (
currentContext &&
typeof currentContext === "object" &&
!Array.isArray(currentContext)
) {
const value = (currentContext as Record<string, json>)[currentKey];
return value === undefined ? null : value;
}
return null;
},
allBlockPropsForSection,
);
return {
blockProps: targetValue === null ? undefined : targetValue,
blockUid,
};
}
return { blockProps: allBlockPropsForSection, blockUid };
const blockProps = getBlockPropsByUid(blockUid, keys.slice(1));

return { blockProps, blockUid };
};

export const setBlockPropBasedSettings = ({
Expand All @@ -78,41 +122,7 @@ export const setBlockPropBasedSettings = ({
title: DG_BLOCK_PROP_SETTINGS_PAGE_TITLE,
});

if (keys.length === 1) {
setBlockProps(blockUid, value as Record<string, json>, false);
return;
}

const currentProps = getBlockProps(blockUid);
const updatedProps = JSON.parse(JSON.stringify(currentProps || {})) as Record<
string,
json
>;

const propertyPath = keys.slice(1);
const lastKeyIndex = propertyPath.length - 1;

propertyPath.reduce<Record<string, json>>(
(currentContext, currentKey, index) => {
if (index === lastKeyIndex) {
currentContext[currentKey] = value;
return currentContext;
}

if (
!currentContext[currentKey] ||
typeof currentContext[currentKey] !== "object" ||
Array.isArray(currentContext[currentKey])
) {
currentContext[currentKey] = {};
}

return currentContext[currentKey] as Record<string, json>;
},
updatedProps,
);

setBlockProps(blockUid, updatedProps, false);
setBlockPropsByUid(blockUid, keys.slice(1), value);
};

export const getFeatureFlag = (key: keyof FeatureFlags): boolean => {
Expand Down Expand Up @@ -188,3 +198,46 @@ export const setPersonalSetting = (keys: string[], value: json): void => {
value,
});
};

export const getDiscourseNodeSettings = (
nodeType: string,
): DiscourseNodeSettings | undefined => {
const pageUid = getDiscourseNodePageUid(nodeType);

if (!pageUid) return undefined;

const blockProps = getBlockPropsByUid(pageUid, []);

if (!blockProps) return undefined;

return DiscourseNodeSchema.parse(blockProps);
};

export const getDiscourseNodeSetting = (
nodeType: string,
keys: string[],
): unknown => {
const settings = getDiscourseNodeSettings(nodeType);

if (!settings) return undefined;

return keys.reduce<unknown>((current, key) => {
if (!isRecord(current) || !(key in current)) return undefined;
return current[key];
}, settings);
};

export const setDiscourseNodeSetting = (
nodeType: string,
keys: string[],
value: json,
): void => {
const pageUid = getDiscourseNodePageUid(nodeType);

if (!pageUid) {
console.warn(`Discourse node page not found for type: ${nodeType}`);
return;
}

setBlockPropsByUid(pageUid, keys, value);
};
57 changes: 57 additions & 0 deletions apps/roam/src/components/settings/block-prop/utils/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@ import {
TOP_LEVEL_BLOCK_PROP_KEYS,
DG_BLOCK_PROP_SETTINGS_PAGE_TITLE,
} from "~/components/settings/block-prop/data/blockPropsSettingsConfig";
import INITIAL_NODE_VALUES from "~/components/settings/block-prop/data/defaultDiscourseNodeValues";
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
import getShallowTreeByParentUid from "roamjs-components/queries/getShallowTreeByParentUid";
import { createPage, createBlock } from "roamjs-components/writes";
import setBlockProps from "~/utils/setBlockProps";
import getBlockProps, { type json } from "~/utils/getBlockProps";
import { DiscourseNodeSchema } from "~/components/settings/block-prop/utils/zodSchema";

export const DISCOURSE_NODE_PAGE_PREFIX = "discourse-graph/nodes/";

const ensurePageExists = async (pageTitle: string): Promise<string> => {
let pageUid = getPageUidByPageTitle(pageTitle);
Expand Down Expand Up @@ -87,3 +93,54 @@ export const initSchema = async (): Promise<Record<string, string>> => {

return blockMap;
};

export const getDiscourseNodePageTitle = (nodeType: string): string => {
return `${DISCOURSE_NODE_PAGE_PREFIX}${nodeType}`;
};

export const getDiscourseNodePageUid = (
nodeType: string,
): string | undefined => {
const pageTitle = getDiscourseNodePageTitle(nodeType);
const pageUid = getPageUidByPageTitle(pageTitle);
return pageUid || undefined;
};

const ensureDiscourseNodePageExists = async (
nodeType: string,
): Promise<string> => {
const pageTitle = getDiscourseNodePageTitle(nodeType);
return ensurePageExists(pageTitle);
};

export const initDiscourseNodes = async (): Promise<
Record<string, string>
> => {
const nodePageUids: Record<string, string> = {};

for (const node of INITIAL_NODE_VALUES) {
if (!node.type) continue;

const pageUid = await ensureDiscourseNodePageExists(node.type);
nodePageUids[node.type] = pageUid;

const existingProps = getBlockProps(pageUid);

if (!existingProps || Object.keys(existingProps).length === 0) {
const nodeData = DiscourseNodeSchema.parse({
text: node.text || "",
type: node.type,
format: node.format || "",
shortcut: node.shortcut || "",
tag: node.tag,
graphOverview: node.graphOverview,
canvasSettings: node.canvasSettings || {},
backedBy: "user",
});

setBlockProps(pageUid, nodeData as Record<string, json>, false);
}
}

return nodePageUids;
};
Loading