Skip to content

Commit 46fa9bc

Browse files
authored
Merge pull request #844 from DiscourseGraphs/eng-1478-port-both-global-and-personal-left-sidebar-to-dual-readers-v2
ENG-1478: Port left sidebar to dual-readers + reactivity
2 parents 3b4c80a + ade239b commit 46fa9bc

9 files changed

Lines changed: 259 additions & 58 deletions

File tree

apps/roam/src/components/LeftSidebarView.tsx

Lines changed: 88 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,27 @@ import {
2121
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
2222
import openBlockInSidebar from "roamjs-components/writes/openBlockInSidebar";
2323
import extractRef from "roamjs-components/util/extractRef";
24+
import { getFormattedConfigTree, notify } from "~/utils/discourseConfigRef";
2425
import {
25-
getFormattedConfigTree,
26-
notify,
27-
subscribe,
28-
} from "~/utils/discourseConfigRef";
29-
import type {
30-
LeftSidebarConfig,
31-
LeftSidebarPersonalSectionConfig,
26+
onSettingChange,
27+
settingKeys,
28+
} from "~/components/settings/utils/settingsEmitter";
29+
import {
30+
type LeftSidebarConfig,
31+
type LeftSidebarPersonalSectionConfig,
32+
mergeGlobalSectionWithAccessor,
33+
mergePersonalSectionsWithAccessor,
3234
} from "~/utils/getLeftSidebarSettings";
35+
import {
36+
getGlobalSetting,
37+
getPersonalSetting,
38+
setGlobalSetting,
39+
setPersonalSetting,
40+
} from "~/components/settings/utils/accessors";
41+
import type {
42+
LeftSidebarGlobalSettings,
43+
PersonalSection,
44+
} from "~/components/settings/utils/zodSchema";
3345
import { createBlock } from "roamjs-components/writes";
3446
import deleteBlock from "roamjs-components/writes/deleteBlock";
3547
import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";
@@ -95,12 +107,18 @@ const toggleFoldedState = ({
95107
setIsOpen,
96108
folded,
97109
parentUid,
110+
isGlobal,
111+
sectionIndex,
98112
}: {
99113
isOpen: boolean;
100114
setIsOpen: Dispatch<SetStateAction<boolean>>;
101115
folded: { uid?: string; value: boolean };
102116
parentUid: string;
117+
isGlobal?: boolean;
118+
sectionIndex?: number;
103119
}) => {
120+
const newFolded = !isOpen;
121+
104122
if (isOpen) {
105123
setIsOpen(false);
106124
if (folded.uid) {
@@ -118,6 +136,17 @@ const toggleFoldedState = ({
118136
folded.uid = newUid;
119137
folded.value = true;
120138
}
139+
140+
if (isGlobal) {
141+
setGlobalSetting(["Left sidebar", "Settings", "Folded"], newFolded);
142+
} else if (sectionIndex !== undefined) {
143+
const sections =
144+
getPersonalSetting<PersonalSection[]>(["Left sidebar"]) || [];
145+
if (sections[sectionIndex]) {
146+
sections[sectionIndex].Settings.Folded = newFolded;
147+
setPersonalSetting(["Left sidebar"], sections);
148+
}
149+
}
121150
};
122151

123152
const SectionChildren = ({
@@ -160,8 +189,10 @@ const SectionChildren = ({
160189

161190
const PersonalSectionItem = ({
162191
section,
192+
sectionIndex,
163193
}: {
164194
section: LeftSidebarPersonalSectionConfig;
195+
sectionIndex: number;
165196
}) => {
166197
const titleRef = parseReference(section.text);
167198
const blockText = useMemo(
@@ -182,6 +213,7 @@ const PersonalSectionItem = ({
182213
setIsOpen,
183214
folded: section.settings.folded,
184215
parentUid: section.settings.uid || "",
216+
sectionIndex,
185217
});
186218
};
187219

@@ -226,9 +258,9 @@ const PersonalSections = ({ config }: { config: LeftSidebarConfig }) => {
226258

227259
return (
228260
<div className="personal-left-sidebar-sections">
229-
{sections.map((section) => (
261+
{sections.map((section, index) => (
230262
<div key={section.uid}>
231-
<PersonalSectionItem section={section} />
263+
<PersonalSectionItem section={section} sectionIndex={index} />
232264
</div>
233265
))}
234266
</div>
@@ -253,6 +285,7 @@ const GlobalSection = ({ config }: { config: LeftSidebarConfig["global"] }) => {
253285
setIsOpen,
254286
folded: config.settings.folded,
255287
parentUid: config.settings.uid,
288+
isGlobal: true,
256289
});
257290
}}
258291
>
@@ -276,22 +309,62 @@ const GlobalSection = ({ config }: { config: LeftSidebarConfig["global"] }) => {
276309
);
277310
};
278311

312+
// TODO(ENG-1471): Remove old-system merge when migration complete — just use accessor values directly.
313+
// See mergeGlobalSectionWithAccessor/mergePersonalSectionsWithAccessor for why the merge exists.
314+
const buildConfig = (): LeftSidebarConfig => {
315+
// Read VALUES from accessor (handles flag routing + mismatch detection)
316+
const globalValues = getGlobalSetting<LeftSidebarGlobalSettings>([
317+
"Left sidebar",
318+
]);
319+
const personalValues = getPersonalSetting<PersonalSection[]>([
320+
"Left sidebar",
321+
]);
322+
323+
// Read UIDs from old system (needed for fold CRUD during dual-write)
324+
const oldConfig = getFormattedConfigTree().leftSidebar;
325+
326+
return {
327+
uid: oldConfig.uid,
328+
favoritesMigrated: oldConfig.favoritesMigrated,
329+
sidebarMigrated: oldConfig.sidebarMigrated,
330+
global: mergeGlobalSectionWithAccessor(oldConfig.global, globalValues),
331+
personal: {
332+
uid: oldConfig.personal.uid,
333+
sections: mergePersonalSectionsWithAccessor(
334+
oldConfig.personal.sections,
335+
personalValues,
336+
),
337+
},
338+
allPersonalSections: oldConfig.allPersonalSections,
339+
};
340+
};
341+
279342
export const useConfig = () => {
280-
const [config, setConfig] = useState(
281-
() => getFormattedConfigTree().leftSidebar,
282-
);
343+
const [config, setConfig] = useState(() => buildConfig());
283344
useEffect(() => {
284345
const handleUpdate = () => {
285-
setConfig(getFormattedConfigTree().leftSidebar);
346+
refreshConfigTree();
347+
setConfig(buildConfig());
286348
};
287-
const unsubscribe = subscribe(handleUpdate);
349+
const unsubGlobal = onSettingChange(
350+
settingKeys.globalLeftSidebar,
351+
handleUpdate,
352+
);
353+
const unsubPersonal = onSettingChange(
354+
settingKeys.personalLeftSidebar,
355+
handleUpdate,
356+
);
288357
return () => {
289-
unsubscribe();
358+
unsubGlobal();
359+
unsubPersonal();
290360
};
291361
}, []);
292362
return { config, setConfig };
293363
};
294364

365+
// TODO(ENG-1471): refreshAndNotify still needed by settings panels
366+
// (LeftSidebarGlobalSettings, LeftSidebarPersonalSettings) for old-system CRUD.
367+
// Remove when settings panels also read via accessors + emitter.
295368
export const refreshAndNotify = () => {
296369
refreshConfigTree();
297370
notify();

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
GlobalTextPanel,
77
FeatureFlagPanel,
88
} from "./components/BlockPropSettingPanels";
9+
import { isNewSettingsStoreEnabled } from "./utils/accessors";
910
import posthog from "posthog-js";
1011

1112
const DiscourseGraphHome = () => {
@@ -43,7 +44,7 @@ const DiscourseGraphHome = () => {
4344
uid={settings.leftSidebarEnabled.uid}
4445
parentUid={settings.settingsUid}
4546
onAfterChange={(checked: boolean) => {
46-
if (checked) {
47+
if (checked && !isNewSettingsStoreEnabled()) {
4748
setIsAlertOpen(true);
4849
}
4950
posthog.capture("General Settings: Left Sidebar Toggled", {

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

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import React, { useCallback, useEffect, useMemo, useState, memo } from "react";
22
import { Button, ButtonGroup, Collapse } from "@blueprintjs/core";
33
import { GlobalFlagPanel } from "~/components/settings/components/BlockPropSettingPanels";
4-
import { setGlobalSetting } from "~/components/settings/utils/accessors";
4+
import {
5+
setGlobalSetting,
6+
getGlobalSetting,
7+
} from "~/components/settings/utils/accessors";
8+
import type { LeftSidebarGlobalSettings } from "~/components/settings/utils/zodSchema";
59
import AutocompleteInput from "roamjs-components/components/AutocompleteInput";
610
import getAllPageNames from "roamjs-components/queries/getAllPageNames";
711
import createBlock from "roamjs-components/writes/createBlock";
@@ -11,8 +15,11 @@ import { extractRef, getSubTree } from "roamjs-components/util";
1115
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
1216
import discourseConfigRef from "~/utils/discourseConfigRef";
1317
import { DISCOURSE_CONFIG_PAGE_TITLE } from "~/utils/renderNodeConfigPage";
14-
import { getLeftSidebarGlobalSectionConfig } from "~/utils/getLeftSidebarSettings";
15-
import { LeftSidebarGlobalSectionConfig } from "~/utils/getLeftSidebarSettings";
18+
import {
19+
getLeftSidebarGlobalSectionConfig,
20+
mergeGlobalSectionWithAccessor,
21+
type LeftSidebarGlobalSectionConfig,
22+
} from "~/utils/getLeftSidebarSettings";
1623
import { render as renderToast } from "roamjs-components/components/Toast";
1724
import refreshConfigTree from "~/utils/refreshConfigTree";
1825
import { refreshAndNotify } from "~/components/LeftSidebarView";
@@ -98,6 +105,9 @@ const LeftSidebarGlobalSectionsContent = ({
98105
const initialize = async () => {
99106
setIsInitializing(true);
100107
const globalSectionText = "Global-Section";
108+
const globalValues = getGlobalSetting<LeftSidebarGlobalSettings>([
109+
"Left sidebar",
110+
]);
101111
const config = getLeftSidebarGlobalSectionConfig(leftSidebar.children);
102112

103113
const existingGlobalSection = leftSidebar.children.find(
@@ -142,9 +152,10 @@ const LeftSidebarGlobalSectionsContent = ({
142152
});
143153
}
144154
} else {
145-
setChildrenUid(config.childrenUid || null);
146-
setPages(config.children || []);
147-
setGlobalSection(config);
155+
const merged = mergeGlobalSectionWithAccessor(config, globalValues);
156+
setChildrenUid(merged.childrenUid || null);
157+
setPages(merged.children || []);
158+
setGlobalSection(merged);
148159
}
149160
setIsInitializing(false);
150161
};

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,19 @@ import createBlock from "roamjs-components/writes/createBlock";
1919
import deleteBlock from "roamjs-components/writes/deleteBlock";
2020
import updateBlock from "roamjs-components/writes/updateBlock";
2121
import type { RoamBasicNode } from "roamjs-components/types";
22-
import { setPersonalSetting } from "~/components/settings/utils/accessors";
22+
import {
23+
setPersonalSetting,
24+
getPersonalSetting,
25+
} from "~/components/settings/utils/accessors";
26+
import type { PersonalSection } from "~/components/settings/utils/zodSchema";
2327
import {
2428
PersonalNumberPanel,
2529
PersonalTextPanel,
2630
} from "~/components/settings/components/BlockPropSettingPanels";
2731
import {
2832
LeftSidebarPersonalSectionConfig,
2933
getLeftSidebarPersonalSectionConfig,
34+
mergePersonalSectionsWithAccessor,
3035
PersonalSectionChild,
3136
} from "~/utils/getLeftSidebarSettings";
3237
import { extractRef, getSubTree } from "roamjs-components/util";
@@ -507,7 +512,7 @@ const SectionItem = memo(
507512
<PersonalTextPanel
508513
title="Alias"
509514
description="Display name for this item"
510-
settingKeys={["Left sidebar"]}
515+
settingKeys={[]}
511516
initialValue={child.alias?.value ?? ""}
512517
order={0}
513518
uid={child.alias?.uid}
@@ -599,10 +604,16 @@ const LeftSidebarPersonalSectionsContent = ({
599604
setSections([]);
600605
} else {
601606
setPersonalSectionUid(personalSection.uid);
607+
608+
const personalValues = getPersonalSetting<PersonalSection[]>([
609+
"Left sidebar",
610+
]);
602611
const loadedSections = getLeftSidebarPersonalSectionConfig(
603612
leftSidebar.children,
604613
).sections;
605-
setSections(loadedSections);
614+
setSections(
615+
mergePersonalSectionsWithAccessor(loadedSections, personalValues),
616+
);
606617
}
607618
};
608619

@@ -786,7 +797,7 @@ const LeftSidebarPersonalSectionsContent = ({
786797
<PersonalNumberPanel
787798
title="Truncate-result?"
788799
description="Maximum characters to display"
789-
settingKeys={["Left sidebar"]}
800+
settingKeys={[]}
790801
initialValue={
791802
activeDialogSection.settings.truncateResult?.value ?? 75
792803
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ const getLegacyPersonalLeftSidebarSetting = (): unknown[] => {
198198
return settings.leftSidebar.personal.sections.map((section) => ({
199199
name: section.text,
200200
Children: (section.children || []).map((child) => ({
201-
uid: child.uid,
201+
uid: child.text,
202202
Alias: child.alias?.value || "",
203203
})),
204204
Settings: {
@@ -724,6 +724,8 @@ export const getGlobalSettings = (): GlobalSettings => {
724724
export const getGlobalSetting = <T = unknown>(
725725
keys: string[],
726726
): T | undefined => {
727+
if (keys.length === 0) return undefined;
728+
727729
if (!isNewSettingsStoreEnabled()) {
728730
return getLegacyGlobalSetting(keys) as T | undefined;
729731
}
@@ -788,6 +790,8 @@ export const getPersonalSettings = (): PersonalSettings => {
788790
export const getPersonalSetting = <T = unknown>(
789791
keys: string[],
790792
): T | undefined => {
793+
if (keys.length === 0) return undefined;
794+
791795
if (!isNewSettingsStoreEnabled()) {
792796
return getLegacyPersonalSetting(keys) as T | undefined;
793797
}

0 commit comments

Comments
 (0)