Skip to content
Draft
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
26 changes: 26 additions & 0 deletions apps/roam/src/components/settings/block-prop/utils/accessors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {
FeatureFlags,
FeatureFlagsSchema,
GlobalSettingsSchema,
PersonalSettingsSchema,
} from "~/components/settings/block-prop/utils/zodSchema";
import { getPersonalSettingsKey } from "~/components/settings/block-prop/utils/init";

const isRecord = (value: unknown): value is Record<string, unknown> =>
typeof value === "object" && value !== null && !Array.isArray(value);
Expand Down Expand Up @@ -162,3 +164,27 @@ export const setGlobalSetting = (keys: string[], value: json): void => {
value,
});
};

export const getPersonalSetting = (keys: string[]): unknown => {
const personalKey = getPersonalSettingsKey();

const { blockProps } = getBlockPropBasedSettings({
keys: [personalKey],
});

const settings = PersonalSettingsSchema.parse(blockProps || {});

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

export const setPersonalSetting = (keys: string[], value: json): void => {
const personalKey = getPersonalSettingsKey();

void setBlockPropBasedSettings({
keys: [personalKey, ...keys],
value,
});
};
89 changes: 89 additions & 0 deletions apps/roam/src/components/settings/block-prop/utils/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {
TOP_LEVEL_BLOCK_PROP_KEYS,
DG_BLOCK_PROP_SETTINGS_PAGE_TITLE,
} from "~/components/settings/block-prop/data/blockPropsSettingsConfig";
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
import getShallowTreeByParentUid from "roamjs-components/queries/getShallowTreeByParentUid";
import { createPage, createBlock } from "roamjs-components/writes";

const ensurePageExists = async (pageTitle: string): Promise<string> => {
let pageUid = getPageUidByPageTitle(pageTitle);

if (!pageUid) {
pageUid = window.roamAlphaAPI.util.generateUID();
await createPage({
title: pageTitle,
uid: pageUid,
});
}

return pageUid;
};

const ensureBlocksExist = async (
pageUid: string,
blockMap: Record<string, string>,
): Promise<Record<string, string>> => {
const blockTexts = Object.values(TOP_LEVEL_BLOCK_PROP_KEYS);

const missingBlocks = blockTexts.filter((blockText) => !blockMap[blockText]);

if (missingBlocks.length > 0) {
const createdBlocks = await Promise.all(
missingBlocks.map(async (blockText) => {
const uid = await createBlock({
parentUid: pageUid,
node: { text: blockText },
});
return { text: blockText, uid };
}),
);

createdBlocks.forEach((block) => {
blockMap[block.text] = block.uid;
});
}

return blockMap;
};

const ensurePersonalBlockExists = async (
pageUid: string,
blockMap: Record<string, string>,
): Promise<{ key: string; uid: string }> => {
const userUid = window.roamAlphaAPI.user.uid();
const personalKey = `${userUid}/Personal-Section`;

if (blockMap[personalKey]) {
return { key: personalKey, uid: blockMap[personalKey] };
}

const uid = await createBlock({
parentUid: pageUid,
node: { text: personalKey },
});

return { key: personalKey, uid };
};

export const getPersonalSettingsKey = (): string => {
const userUid = window.roamAlphaAPI.user.uid();
return `${userUid}/Personal-Section`;
};

export const initSchema = async (): Promise<Record<string, string>> => {
const pageUid = await ensurePageExists(DG_BLOCK_PROP_SETTINGS_PAGE_TITLE);
const existingChildren = getShallowTreeByParentUid(pageUid);

const blockMap: Record<string, string> = {};
existingChildren.forEach((child) => {
blockMap[child.text] = child.uid;
});

await ensureBlocksExist(pageUid, blockMap);

const personalBlock = await ensurePersonalBlockExists(pageUid, blockMap);
blockMap[personalBlock.key] = personalBlock.uid;

return blockMap;
};
54 changes: 36 additions & 18 deletions apps/roam/src/components/settings/block-prop/utils/pullWatch.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
import { TOP_LEVEL_BLOCK_PROP_KEYS } from "~/components/settings/block-prop/data/blockPropsSettingsConfig";
import { type json, normalizeProps } from "~/utils/getBlockProps";
import { getPersonalSettingsKey } from "~/components/settings/block-prop/utils/init";

const hasPropChanged = (
before: unknown,
after: unknown,
key: string,
): boolean => {
const beforeProps = normalizeProps(
((before as Record<string, unknown>)?.[":block/props"] || {}) as json,
) as Record<string, json>;
const afterProps = normalizeProps(
((after as Record<string, unknown>)?.[":block/props"] || {}) as json,
) as Record<string, json>;

return JSON.stringify(beforeProps[key]) !== JSON.stringify(afterProps[key]);
};

export const setupPullWatchBlockPropsBasedSettings = (
blockUids: Record<string, string>,
Expand All @@ -16,22 +32,7 @@ export const setupPullWatchBlockPropsBasedSettings = (
"[:block/props]",
`[:block/uid "${featureFlagsBlockUid}"]`,
(before, after) => {
const beforeProps = normalizeProps(
(before?.[":block/props"] || {}) as json,
) as Record<string, json>;
const afterProps = normalizeProps(
(after?.[":block/props"] || {}) as json,
) as Record<string, json>;

const beforeEnabled = beforeProps["Enable Left Sidebar"] as
| boolean
| undefined;
const afterEnabled = afterProps["Enable Left Sidebar"] as
| boolean
| undefined;

// Only update if the flag actually changed
if (beforeEnabled !== afterEnabled) {
if (hasPropChanged(before, after, "Enable Left Sidebar")) {
updateLeftSidebar(leftSidebarContainer);
}
},
Expand All @@ -42,8 +43,25 @@ export const setupPullWatchBlockPropsBasedSettings = (
window.roamAlphaAPI.data.addPullWatch(
"[:block/props]",
`[:block/uid "${globalSettingsBlockUid}"]`,
() => {
updateLeftSidebar(leftSidebarContainer);
(before, after) => {
if (hasPropChanged(before, after, "Left Sidebar")) {
updateLeftSidebar(leftSidebarContainer);
}
},
);
}

const personalSettingsKey = getPersonalSettingsKey();
const personalSettingsBlockUid = blockUids[personalSettingsKey];

if (personalSettingsBlockUid) {
window.roamAlphaAPI.data.addPullWatch(
"[:block/props]",
`[:block/uid "${personalSettingsBlockUid}"]`,
(before, after) => {
if (hasPropChanged(before, after, "Left Sidebar")) {
updateLeftSidebar(leftSidebarContainer);
}
},
);
}
Expand Down
47 changes: 47 additions & 0 deletions apps/roam/src/components/settings/block-prop/utils/zodSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { z } from "zod";

/* eslint-disable @typescript-eslint/naming-convention */
export const FeatureFlagsSchema = z.object({
"Enable Left Sidebar": z.boolean().default(false),
});

export const GlobalSettingsSchema = z.object({
"Left Sidebar": z
.object({
Children: z.array(z.string()).default([]),
Settings: z
.object({
Collapsable: z.boolean().default(false),
Folded: z.boolean().default(false),
})
.default({}),
})
.default({}),
});

export const PersonalSectionSchema = z.object({
Children: z
.array(
z.object({
Page: z.string(),
Alias: z.string().default(""),
}),
)
.default([]),
Settings: z
.object({
"Truncate-result?": z.number().default(75),
Folded: z.boolean().default(false),
})
.default({}),
});

export const PersonalSettingsSchema = z.object({
"Left Sidebar": z.record(z.string(), PersonalSectionSchema).default({}),
});
/* eslint-enable @typescript-eslint/naming-convention */

export type FeatureFlags = z.infer<typeof FeatureFlagsSchema>;
export type GlobalSettings = z.infer<typeof GlobalSettingsSchema>;
export type PersonalSection = z.infer<typeof PersonalSectionSchema>;
export type PersonalSettings = z.infer<typeof PersonalSettingsSchema>;
Loading