Skip to content
Closed
111 changes: 105 additions & 6 deletions apps/roam/src/components/LeftSidebarView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ import type {
LeftSidebarConfig,
LeftSidebarPersonalSectionConfig,
} from "~/utils/getLeftSidebarSettings";
import {
getGlobalSetting,
getPersonalSetting,
setGlobalSetting,
setPersonalSetting,
} from "~/components/settings/utils/accessors";
import type {
LeftSidebarGlobalSettings,
PersonalSection,
} from "~/components/settings/utils/zodSchema";
import { createBlock } from "roamjs-components/writes";
import deleteBlock from "roamjs-components/writes/deleteBlock";
import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";
Expand Down Expand Up @@ -95,12 +105,18 @@ const toggleFoldedState = ({
setIsOpen,
folded,
parentUid,
isGlobal,
sectionIndex,
}: {
isOpen: boolean;
setIsOpen: Dispatch<SetStateAction<boolean>>;
folded: { uid?: string; value: boolean };
parentUid: string;
isGlobal?: boolean;
sectionIndex?: number;
}) => {
const newFolded = !isOpen;

if (isOpen) {
setIsOpen(false);
if (folded.uid) {
Expand All @@ -118,6 +134,18 @@ const toggleFoldedState = ({
folded.uid = newUid;
folded.value = true;
}

// Dual-write to block props
if (isGlobal) {
setGlobalSetting(["Left sidebar", "Settings", "Folded"], newFolded);
} else if (sectionIndex !== undefined) {
const sections =
getPersonalSetting<PersonalSection[]>(["Left sidebar"]) || [];
if (sections[sectionIndex]) {
sections[sectionIndex].Settings.Folded = newFolded;
setPersonalSetting(["Left sidebar"], sections);
}
}
};

const SectionChildren = ({
Expand Down Expand Up @@ -160,8 +188,10 @@ const SectionChildren = ({

const PersonalSectionItem = ({
section,
sectionIndex,
}: {
section: LeftSidebarPersonalSectionConfig;
sectionIndex: number;
}) => {
const titleRef = parseReference(section.text);
const blockText = useMemo(
Expand All @@ -182,6 +212,7 @@ const PersonalSectionItem = ({
setIsOpen,
folded: section.settings.folded,
parentUid: section.settings.uid || "",
sectionIndex,
});
};

Expand Down Expand Up @@ -226,9 +257,9 @@ const PersonalSections = ({ config }: { config: LeftSidebarConfig }) => {

return (
<div className="personal-left-sidebar-sections">
{sections.map((section) => (
{sections.map((section, index) => (
<div key={section.uid}>
<PersonalSectionItem section={section} />
<PersonalSectionItem section={section} sectionIndex={index} />
</div>
))}
</div>
Expand All @@ -253,6 +284,7 @@ const GlobalSection = ({ config }: { config: LeftSidebarConfig["global"] }) => {
setIsOpen,
folded: config.settings.folded,
parentUid: config.settings.uid,
isGlobal: true,
});
}}
>
Expand All @@ -276,13 +308,80 @@ const GlobalSection = ({ config }: { config: LeftSidebarConfig["global"] }) => {
);
};

const buildConfig = (): LeftSidebarConfig => {
// Read VALUES from accessor (handles flag routing + mismatch detection)
const globalValues = getGlobalSetting<LeftSidebarGlobalSettings>([
"Left sidebar",
]);
const personalValues = getPersonalSetting<PersonalSection[]>([
"Left sidebar",
]);

// Read UIDs from old system (needed for fold CRUD during dual-write)
const oldConfig = getFormattedConfigTree().leftSidebar;

// Merge: accessor values + old-system UIDs
return {
uid: oldConfig.uid,
favoritesMigrated: oldConfig.favoritesMigrated,
sidebarMigrated: oldConfig.sidebarMigrated,
global: {
uid: oldConfig.global.uid,
childrenUid: oldConfig.global.childrenUid,
children: oldConfig.global.children,
settings: oldConfig.global.settings
? {
uid: oldConfig.global.settings.uid,
collapsable: {
uid: oldConfig.global.settings.collapsable.uid,
value:
globalValues?.Settings?.Collapsable ??
oldConfig.global.settings.collapsable.value,
},
folded: {
uid: oldConfig.global.settings.folded.uid,
value:
globalValues?.Settings?.Folded ??
oldConfig.global.settings.folded.value,
},
}
: undefined,
},
personal: {
uid: oldConfig.personal.uid,
sections: oldConfig.personal.sections.map((oldSection, i) => {
const newSection = personalValues?.[i];
return {
...oldSection,
settings: oldSection.settings
? {
...oldSection.settings,
truncateResult: {
...oldSection.settings.truncateResult,
value:
newSection?.Settings?.["Truncate-result?"] ??
oldSection.settings.truncateResult.value,
},
folded: {
...oldSection.settings.folded,
value:
newSection?.Settings?.Folded ??
oldSection.settings.folded.value,
},
}
: oldSection.settings,
};
}),
},
allPersonalSections: oldConfig.allPersonalSections,
};
};

export const useConfig = () => {
const [config, setConfig] = useState(
() => getFormattedConfigTree().leftSidebar,
);
const [config, setConfig] = useState(() => buildConfig());
useEffect(() => {
const handleUpdate = () => {
setConfig(getFormattedConfigTree().leftSidebar);
setConfig(buildConfig());
};
const unsubscribe = subscribe(handleUpdate);
return () => {
Expand Down
2 changes: 0 additions & 2 deletions apps/roam/src/components/settings/AdminPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import { USE_REIFIED_RELATIONS } from "~/data/userSettings";
import posthog from "posthog-js";
import { setFeatureFlag } from "~/components/settings/utils/accessors";
import { FeatureFlagPanel } from "./components/BlockPropSettingPanels";
import { getFeatureFlag } from "./utils/accessors";

const NodeRow = ({ node }: { node: PConceptFull }) => {
return (
Expand Down Expand Up @@ -473,7 +472,6 @@ const FeatureFlagsTab = (): React.ReactElement => {
title="Use new settings store"
description="When enabled, accessor getters read from block props instead of the old system. Surfaces dual-write gaps during development."
featureKey="Use new settings store"
initialValue={getFeatureFlag("Use new settings store")}
/>

<Button
Expand Down
1 change: 0 additions & 1 deletion apps/roam/src/components/settings/GeneralSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ const DiscourseGraphHome = () => {
<FeatureFlagPanel
title="(BETA) Left Sidebar"
description="Whether or not to enable the left sidebar."
initialValue={settings.leftSidebarEnabled.value}
featureKey="Enable left sidebar"
order={2}
uid={settings.leftSidebarEnabled.uid}
Expand Down
10 changes: 9 additions & 1 deletion apps/roam/src/components/settings/LeftSidebarGlobalSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React, { useCallback, useEffect, useMemo, useState, memo } from "react";
import { Button, ButtonGroup, Collapse } from "@blueprintjs/core";
import { GlobalFlagPanel } from "~/components/settings/components/BlockPropSettingPanels";
import { setGlobalSetting } from "~/components/settings/utils/accessors";
import {
setGlobalSetting,
getGlobalSetting,
} from "~/components/settings/utils/accessors";
import type { LeftSidebarGlobalSettings } from "~/components/settings/utils/zodSchema";
import AutocompleteInput from "roamjs-components/components/AutocompleteInput";
import getAllPageNames from "roamjs-components/queries/getAllPageNames";
import createBlock from "roamjs-components/writes/createBlock";
Expand Down Expand Up @@ -98,6 +102,10 @@ const LeftSidebarGlobalSectionsContent = ({
const initialize = async () => {
setIsInitializing(true);
const globalSectionText = "Global-Section";
// Dual-read: accessor validates values and logs mismatches when flag ON
getGlobalSetting<LeftSidebarGlobalSettings>(["Left sidebar"]);

// Use old system data (has UIDs needed for CRUD operations)
const config = getLeftSidebarGlobalSectionConfig(leftSidebar.children);

const existingGlobalSection = leftSidebar.children.find(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,11 @@ import createBlock from "roamjs-components/writes/createBlock";
import deleteBlock from "roamjs-components/writes/deleteBlock";
import updateBlock from "roamjs-components/writes/updateBlock";
import type { RoamBasicNode } from "roamjs-components/types";
import { setPersonalSetting } from "~/components/settings/utils/accessors";
import {
setPersonalSetting,
getPersonalSetting,
} from "~/components/settings/utils/accessors";
import type { PersonalSection } from "~/components/settings/utils/zodSchema";
import {
PersonalNumberPanel,
PersonalTextPanel,
Expand Down Expand Up @@ -599,6 +603,11 @@ const LeftSidebarPersonalSectionsContent = ({
setSections([]);
} else {
setPersonalSectionUid(personalSection.uid);

// Dual-read: accessor validates values and logs mismatches when flag ON
getPersonalSetting<PersonalSection[]>(["Left sidebar"]);

// Use old system data (has UIDs needed for CRUD operations)
const loadedSections = getLeftSidebarPersonalSectionConfig(
leftSidebar.children,
).sections;
Expand Down
Loading