Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
18 changes: 8 additions & 10 deletions apps/roam/src/components/DiscourseFloatingMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { FeedbackWidget } from "./BirdEatsBugs";
import { render as renderSettings } from "~/components/settings/Settings";
import posthog from "posthog-js";
import { getPersonalSetting } from "./settings/utils/accessors";
import { type SettingsSnapshot } from "./settings/utils/accessors";
import { PERSONAL_KEYS } from "./settings/utils/settingKeys";

type DiscourseFloatingMenuProps = {
Expand Down Expand Up @@ -118,26 +118,23 @@ export const showDiscourseFloatingMenu = () => {

export const installDiscourseFloatingMenu = (
onLoadArgs: OnloadArgs,
props: DiscourseFloatingMenuProps = {
position: "bottom-right",
theme: "bp3-light",
buttonTheme: "bp3-light",
},
snapshot: SettingsSnapshot,
) => {
let floatingMenuAnchor = document.getElementById(ANCHOR_ID);
if (!floatingMenuAnchor) {
floatingMenuAnchor = document.createElement("div");
floatingMenuAnchor.id = ANCHOR_ID;
document.getElementById("app")?.appendChild(floatingMenuAnchor);
}
if (getPersonalSetting<boolean>([PERSONAL_KEYS.hideFeedbackButton])) {
if (snapshot.personalSettings[PERSONAL_KEYS.hideFeedbackButton]) {
floatingMenuAnchor.classList.add("hidden");
}
// eslint-disable-next-line react/no-deprecated
ReactDOM.render(
<DiscourseFloatingMenu
position={props.position}
theme={props.theme}
buttonTheme={props.buttonTheme}
position="bottom-right"
theme="bp3-light"
buttonTheme="bp3-light"
onloadArgs={onLoadArgs}
/>,
floatingMenuAnchor,
Expand All @@ -148,6 +145,7 @@ export const removeDiscourseFloatingMenu = () => {
const anchor = document.getElementById(ANCHOR_ID);
if (anchor) {
try {
// eslint-disable-next-line react/no-deprecated
ReactDOM.unmountComponentAtNode(anchor);
} catch (e) {
// no-op: unmount best-effort
Expand Down
97 changes: 63 additions & 34 deletions apps/roam/src/components/LeftSidebarView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,19 +36,18 @@ import { getLeftSidebarSettings } from "~/utils/getLeftSidebarSettings";
import {
getGlobalSetting,
getPersonalSetting,
getPersonalSettings,
setGlobalSetting,
setPersonalSetting,
type SettingsSnapshot,
} from "~/components/settings/utils/accessors";
import {
PERSONAL_KEYS,
GLOBAL_KEYS,
LEFT_SIDEBAR_KEYS,
LEFT_SIDEBAR_SETTINGS_KEYS,
} from "~/components/settings/utils/settingKeys";
import type {
LeftSidebarGlobalSettings,
PersonalSection,
} from "~/components/settings/utils/zodSchema";
import type { LeftSidebarGlobalSettings } 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 @@ -112,7 +111,7 @@ const openTarget = async (e: React.MouseEvent, targetUid: string) => {
}
};

const toggleFoldedState = ({
const toggleFoldedState = async ({
isOpen,
setIsOpen,
folded,
Expand All @@ -130,23 +129,26 @@ const toggleFoldedState = ({
const newFolded = !isOpen;

if (isOpen) {
setIsOpen(false);
if (folded.uid) {
void deleteBlock(folded.uid);
folded.uid = undefined;
folded.value = false;
}
const children = getBasicTreeByParentUid(parentUid);
await Promise.all(
children
.filter((c) => c.text === "Folded")
.map((c) => deleteBlock(c.uid)),
);
folded.uid = undefined;
folded.value = false;
} else {
setIsOpen(true);
const newUid = window.roamAlphaAPI.util.generateUID();
void createBlock({
await createBlock({
parentUid,
node: { text: "Folded", uid: newUid },
});
folded.uid = newUid;
folded.value = true;
}

refreshConfigTree();

if (isGlobal) {
setGlobalSetting(
[
Expand All @@ -157,13 +159,20 @@ const toggleFoldedState = ({
newFolded,
);
} else if (sectionIndex !== undefined) {
const sections =
getPersonalSetting<PersonalSection[]>([PERSONAL_KEYS.leftSidebar]) || [];
const sections = [...getPersonalSettings()[PERSONAL_KEYS.leftSidebar]];
if (sections[sectionIndex]) {
sections[sectionIndex].Settings.Folded = newFolded;
sections[sectionIndex] = {
...sections[sectionIndex],
Settings: {
...sections[sectionIndex].Settings,
Folded: newFolded,
},
};
setPersonalSetting([PERSONAL_KEYS.leftSidebar], sections);
}
}

setIsOpen(newFolded);
Comment thread
sid597 marked this conversation as resolved.
};

const SectionChildren = ({
Expand Down Expand Up @@ -225,7 +234,7 @@ const PersonalSectionItem = ({
const handleChevronClick = () => {
if (!section.settings) return;

toggleFoldedState({
void toggleFoldedState({
isOpen,
setIsOpen,
folded: section.settings.folded,
Expand Down Expand Up @@ -297,7 +306,7 @@ const GlobalSection = ({ config }: { config: LeftSidebarConfig["global"] }) => {
className="sidebar-title-button flex w-full items-center border-none bg-transparent py-1 pl-6 pr-2.5 font-semibold outline-none"
onClick={() => {
if (!isCollapsable || !config.settings) return;
toggleFoldedState({
void toggleFoldedState({
isOpen,
setIsOpen,
folded: config.settings.folded,
Expand Down Expand Up @@ -328,14 +337,16 @@ const GlobalSection = ({ config }: { config: LeftSidebarConfig["global"] }) => {

// TODO(ENG-1471): Remove old-system merge when migration complete — just use accessor values directly.
// See mergeGlobalSectionWithAccessor/mergePersonalSectionsWithAccessor for why the merge exists.
const buildConfig = (): LeftSidebarConfig => {
const buildConfig = (snapshot?: SettingsSnapshot): LeftSidebarConfig => {
// Read VALUES from accessor (handles flag routing + mismatch detection)
const globalValues = getGlobalSetting<LeftSidebarGlobalSettings>([
GLOBAL_KEYS.leftSidebar,
]);
const personalValues = getPersonalSetting<PersonalSection[]>([
PERSONAL_KEYS.leftSidebar,
]);
const globalValues = snapshot
? snapshot.globalSettings[GLOBAL_KEYS.leftSidebar]
: getGlobalSetting<LeftSidebarGlobalSettings>([GLOBAL_KEYS.leftSidebar]);
const personalValues = snapshot
? snapshot.personalSettings[PERSONAL_KEYS.leftSidebar]
: getPersonalSetting<
ReturnType<typeof getPersonalSettings>[typeof PERSONAL_KEYS.leftSidebar]
>([PERSONAL_KEYS.leftSidebar]);

// Read UIDs from old system (needed for fold CRUD during dual-write)
const oldConfig = getCurrentLeftSidebarConfig();
Expand All @@ -356,8 +367,8 @@ const buildConfig = (): LeftSidebarConfig => {
};
};

export const useConfig = () => {
const [config, setConfig] = useState(() => buildConfig());
export const useConfig = (initialSnapshot?: SettingsSnapshot) => {
const [config, setConfig] = useState(() => buildConfig(initialSnapshot));
useEffect(() => {
const handleUpdate = () => {
setConfig(buildConfig());
Expand Down Expand Up @@ -496,8 +507,14 @@ const FavoritesPopover = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
);
};

const LeftSidebarView = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
const { config } = useConfig();
const LeftSidebarView = ({
onloadArgs,
initialSnapshot,
}: {
onloadArgs: OnloadArgs;
initialSnapshot?: SettingsSnapshot;
}) => {
const { config } = useConfig(initialSnapshot);

return (
<>
Expand Down Expand Up @@ -602,10 +619,15 @@ const migrateFavorites = async () => {
refreshConfigTree();
};

export const mountLeftSidebar = async (
wrapper: HTMLElement,
onloadArgs: OnloadArgs,
): Promise<void> => {
export const mountLeftSidebar = async ({
wrapper,
onloadArgs,
initialSnapshot,
}: {
wrapper: HTMLElement;
onloadArgs: OnloadArgs;
initialSnapshot?: SettingsSnapshot;
}): Promise<void> => {
if (!wrapper) return;

const id = "dg-left-sidebar-root";
Expand All @@ -622,7 +644,14 @@ export const mountLeftSidebar = async (
} else {
root.className = "starred-pages";
}
ReactDOM.render(<LeftSidebarView onloadArgs={onloadArgs} />, root);
// eslint-disable-next-line react/no-deprecated
ReactDOM.render(
<LeftSidebarView
onloadArgs={onloadArgs}
initialSnapshot={initialSnapshot}
/>,
root,
);
};

export default LeftSidebarView;
18 changes: 11 additions & 7 deletions apps/roam/src/components/settings/AdminPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ const FeatureFlagsTab = (): React.ReactElement => {
};
}, []);

const [suggestiveModeEnabled, setSuggestiveModeEnabled] = useState(
const [suggestiveModeEnabled, setSuggestiveModeEnabled] = useState(() =>
getFeatureFlag("Suggestive mode enabled"),
);
const [suggestiveModeUid, setSuggestiveModeUid] = useState(
Expand All @@ -294,12 +294,15 @@ const FeatureFlagsTab = (): React.ReactElement => {
if (checked) {
setIsAlertOpen(true);
} else {
if (suggestiveModeUid) {
void deleteBlock(suggestiveModeUid);
setSuggestiveModeUid(undefined);
}
setSuggestiveModeEnabled(false);
setFeatureFlag("Suggestive mode enabled", false);
void (async () => {
if (suggestiveModeUid) {
await deleteBlock(suggestiveModeUid);
setSuggestiveModeUid(undefined);
}
refreshConfigTree();
setSuggestiveModeEnabled(false);
setFeatureFlag("Suggestive mode enabled", false);
})();
}
}}
labelElement={
Expand All @@ -321,6 +324,7 @@ const FeatureFlagsTab = (): React.ReactElement => {
node: { text: "(BETA) Suggestive Mode Enabled" },
}).then((uid) => {
setSuggestiveModeUid(uid);
refreshConfigTree();
setSuggestiveModeEnabled(true);
setFeatureFlag("Suggestive mode enabled", true);
setIsAlertOpen(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,13 @@ const DiscourseNodeCanvasSettings = ({
settingKeys={[DISCOURSE_NODE_KEYS.canvasSettings, CANVAS_KEYS.keyImage]}
initialValue={isKeyImage}
onChange={(checked) => {
setIsKeyImage(checked);
if (checked && !keyImageOption) setKeyImageOption("first-image");
void setInputSetting({
blockUid: uid,
key: "key-image",
value: checked ? "true" : "false",
});
setTimeout(() => setIsKeyImage(checked), 100);
}}
/>
<RadioGroup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,9 @@ const SectionItem = memo(
order: 0,
node: { text: "Settings" },
});
const foldedUid = await createBlock({
parentUid: settingsUid,
order: 0,
node: { text: "Folded" },
});
const truncateSettingUid = await createBlock({
parentUid: settingsUid,
order: 1,
order: 0,
node: { text: "Truncate-result?", children: [{ text: "75" }] },
});

Expand All @@ -149,7 +144,7 @@ const SectionItem = memo(
...s,
settings: {
uid: settingsUid,
folded: { uid: foldedUid, value: false },
folded: { uid: undefined, value: false },
truncateResult: { uid: truncateSettingUid, value: 75 },
},
childrenUid,
Expand All @@ -167,7 +162,7 @@ const SectionItem = memo(
...s,
settings: {
uid: settingsUid,
folded: { uid: foldedUid, value: false },
folded: { uid: undefined, value: false },
truncateResult: { uid: truncateSettingUid, value: 75 },
},
children: [],
Expand Down
13 changes: 8 additions & 5 deletions apps/roam/src/components/settings/QueryPagesPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { OnloadArgs } from "roamjs-components/types";
import {
getPersonalSetting,
setPersonalSetting,
type SettingsSnapshot,
} from "~/components/settings/utils/accessors";
import {
PERSONAL_KEYS,
Expand All @@ -13,11 +14,13 @@ import {

// Legacy extensionAPI stored query-pages as string | string[] | Record<string, string>.
// Coerce to string[] for backward compatibility with old stored formats.
export const getQueryPages = (): string[] => {
const value = getPersonalSetting<string[] | string | Record<string, string>>([
PERSONAL_KEYS.query,
QUERY_KEYS.queryPages,
]);
export const getQueryPages = (snapshot?: SettingsSnapshot): string[] => {
const value: string[] | string | Record<string, string> | undefined = snapshot
? snapshot.personalSettings[PERSONAL_KEYS.query][QUERY_KEYS.queryPages]
: getPersonalSetting<string[] | string | Record<string, string>>([
PERSONAL_KEYS.query,
QUERY_KEYS.queryPages,
]);
return typeof value === "string"
? [value]
: Array.isArray(value)
Expand Down
Loading
Loading