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
48 changes: 28 additions & 20 deletions apps/roam/src/components/LeftSidebarView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import type {
LeftSidebarConfig,
LeftSidebarPersonalSectionConfig,
} from "~/utils/getLeftSidebarSettings";
import type { BooleanSetting } from "~/utils/getExportSettings";
import { createBlock } from "roamjs-components/writes";
import deleteBlock from "roamjs-components/writes/deleteBlock";
import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";
Expand All @@ -41,6 +40,8 @@ import { OnloadArgs } from "roamjs-components/types";
import renderOverlay from "roamjs-components/util/renderOverlay";
import getBasicTreeByParentUid from "roamjs-components/queries/getBasicTreeByParentUid";
import { DISCOURSE_CONFIG_PAGE_TITLE } from "~/utils/renderNodeConfigPage";
import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
import { migrateLeftSidebarSettings } from "~/utils/migrateLeftSidebarSettings";

const parseReference = (text: string) => {
const extracted = extractRef(text);
Expand All @@ -56,10 +57,10 @@ const truncate = (s: string, max: number | undefined): string => {
return s.length > max ? `${s.slice(0, max)}...` : s;
};

const openTarget = async (e: React.MouseEvent, sectionTitle: string) => {
const openTarget = async (e: React.MouseEvent, targetUid: string) => {
e.preventDefault();
e.stopPropagation();
const target = parseReference(sectionTitle);
const target = parseReference(targetUid);
if (target.type === "block") {
if (e.shiftKey) {
await openBlockInSidebar(target.uid);
Expand All @@ -71,16 +72,16 @@ const openTarget = async (e: React.MouseEvent, sectionTitle: string) => {
return;
}

const uid = getPageUidByPageTitle(sectionTitle);
if (!uid) return;
if (e.shiftKey) {
await window.roamAlphaAPI.ui.rightSidebar.addWindow({
// @ts-expect-error - todo test
// eslint-disable-next-line @typescript-eslint/naming-convention
window: { type: "outline", "block-uid": uid },
window: { type: "outline", "block-uid": targetUid },
});
} else {
await window.roamAlphaAPI.ui.mainWindow.openPage({ page: { uid } });
await window.roamAlphaAPI.ui.mainWindow.openPage({
page: { uid: targetUid },
});
}
};

Expand Down Expand Up @@ -127,7 +128,11 @@ const SectionChildren = ({
{childrenNodes.map((child) => {
const ref = parseReference(child.text);
const alias = child.alias?.value;
const label = alias || truncate(ref.display, truncateAt);
const display =
ref.type === "page"
? getPageTitleByPageUid(ref.display)
: getTextByBlockUid(ref.uid);
const label = alias || truncate(display, truncateAt);
const onClick = (e: React.MouseEvent) => {
return void openTarget(e, child.text);
};
Expand Down Expand Up @@ -184,7 +189,7 @@ const PersonalSectionItem = ({
onClick={() => {
if ((section.children?.length || 0) > 0) {
handleChevronClick();
}
}
}}
>
{(blockText || titleRef.display).toUpperCase()}
Expand Down Expand Up @@ -410,13 +415,13 @@ const LeftSidebarView = ({ onloadArgs }: { onloadArgs: OnloadArgs }) => {
};

const migrateFavorites = async () => {
const configPageUid = getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE);
if (!configPageUid) return;

const config = getFormattedConfigTree().leftSidebar;

if (config.favoritesMigrated.value) return;

const configPageUid = getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE);
if (!configPageUid) return;

let leftSidebarUid = config.uid;
if (leftSidebarUid) {
const leftSidebarTree = getBasicTreeByParentUid(leftSidebarUid);
Expand All @@ -434,11 +439,13 @@ const migrateFavorites = async () => {
}

const results = window.roamAlphaAPI.q(`
[:find ?title
[:find ?uid
:where [?e :page/sidebar]
[?e :node/title ?title]]
[?e :block/uid ?uid]]
`);
const titles = (results as string[][]).map(([title]) => title);
const favorites = (results as string[][]).map(([uid]) => ({
uid,
}));

if (!leftSidebarUid) {
const tree = getBasicTreeByParentUid(configPageUid);
Expand Down Expand Up @@ -482,13 +489,13 @@ const migrateFavorites = async () => {
}

const childrenTree = getBasicTreeByParentUid(childrenUid);
const existingTitles = new Set(childrenTree.map((c) => c.text));
const newTitles = titles.filter((t) => !existingTitles.has(t));
const existingTexts = new Set(childrenTree.map((c) => c.text));
const newFavorites = favorites.filter(({ uid }) => !existingTexts.has(uid));

if (newTitles.length > 0) {
if (newFavorites.length > 0) {
await Promise.all(
newTitles.map((text) =>
createBlock({ parentUid: childrenUid, node: { text } }),
newFavorites.map(({ uid }) =>
createBlock({ parentUid: childrenUid, node: { text: uid } }),
),
);
refreshAndNotify();
Expand All @@ -511,6 +518,7 @@ export const mountLeftSidebar = async (
let root = wrapper.querySelector(`#${id}`) as HTMLDivElement;
if (!root) {
await migrateFavorites();
await migrateLeftSidebarSettings();
wrapper.innerHTML = "";
root = document.createElement("div");
root.id = id;
Expand Down
29 changes: 19 additions & 10 deletions apps/roam/src/components/settings/LeftSidebarGlobalSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import getAllPageNames from "roamjs-components/queries/getAllPageNames";
import createBlock from "roamjs-components/writes/createBlock";
import deleteBlock from "roamjs-components/writes/deleteBlock";
import type { RoamBasicNode } from "roamjs-components/types";
import { getSubTree } from "roamjs-components/util";
import { extractRef, getSubTree } from "roamjs-components/util";
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
import discourseConfigRef from "~/utils/discourseConfigRef";
import { DISCOURSE_CONFIG_PAGE_TITLE } from "~/utils/renderNodeConfigPage";
Expand All @@ -15,6 +15,8 @@ import { LeftSidebarGlobalSectionConfig } from "~/utils/getLeftSidebarSettings";
import { render as renderToast } from "roamjs-components/components/Toast";
import refreshConfigTree from "~/utils/refreshConfigTree";
import { refreshAndNotify } from "~/components/LeftSidebarView";
import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
import getTextByBlockUid from "roamjs-components/queries/getTextByBlockUid";

const PageItem = memo(
({
Expand All @@ -32,10 +34,15 @@ const PageItem = memo(
onMove: (index: number, direction: "up" | "down") => void;
onRemove: (page: RoamBasicNode) => void;
}) => {
const pageDisplayTitle =
getPageTitleByPageUid(page.text) ||
getTextByBlockUid(extractRef(page.text)) ||
page.text;

return (
<div className="group flex items-center justify-between rounded bg-gray-50 p-2 hover:bg-gray-100">
<div className="mr-2 flex-grow truncate">{page.text}</div>
<ButtonGroup minimal>
<div className="mr-2 min-w-0 flex-1 truncate">{pageDisplayTitle}</div>
<ButtonGroup minimal className="flex-shrink-0">
<Button
icon="arrow-up"
small
Expand Down Expand Up @@ -174,7 +181,8 @@ const LeftSidebarGlobalSectionsContent = ({
async (pageName: string) => {
if (!pageName || !childrenUid) return;

if (pages.some((p) => p.text === pageName)) {
const targetUid = getPageUidByPageTitle(pageName);
if (pages.some((p) => p.text === targetUid)) {
console.warn(`Page "${pageName}" already exists in global section`);
return;
}
Expand All @@ -183,11 +191,11 @@ const LeftSidebarGlobalSectionsContent = ({
const newPageUid = await createBlock({
parentUid: childrenUid,
order: "last",
node: { text: pageName },
node: { text: targetUid },
});

const newPage: RoamBasicNode = {
text: pageName,
text: targetUid,
uid: newPageUid,
children: [],
};
Expand Down Expand Up @@ -229,10 +237,11 @@ const LeftSidebarGlobalSectionsContent = ({
setIsExpanded((prev) => !prev);
}, []);

const isAddButtonDisabled = useMemo(
() => !newPageInput || pages.some((p) => p.text === newPageInput),
[newPageInput, pages],
);
const isAddButtonDisabled = useMemo(() => {
if (!newPageInput) return true;
const targetUid = getPageUidByPageTitle(newPageInput);
return !targetUid || pages.some((p) => p.text === targetUid);
}, [newPageInput, pages]);

if (isInitializing || !globalSection) {
return (
Expand Down
19 changes: 13 additions & 6 deletions apps/roam/src/components/settings/LeftSidebarPersonalSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { render as renderToast } from "roamjs-components/components/Toast";
import refreshConfigTree from "~/utils/refreshConfigTree";
import { refreshAndNotify } from "~/components/LeftSidebarView";
import { memo, Dispatch, SetStateAction } from "react";
import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";

const SectionItem = memo(
({
Expand Down Expand Up @@ -155,11 +156,13 @@ const SectionItem = memo(
) => {
if (!childName || !childrenUid) return;

const targetUid = getPageUidByPageTitle(childName) || childName.trim();

try {
const newChild = await createBlock({
parentUid: childrenUid,
order: "last",
node: { text: childName },
node: { text: targetUid },
});

setSections((prev) =>
Expand All @@ -170,7 +173,7 @@ const SectionItem = memo(
children: [
...(s.children || []),
{
text: childName,
text: targetUid,
uid: newChild,
children: [],
alias: { value: "" },
Expand Down Expand Up @@ -378,24 +381,28 @@ const SectionItem = memo(
{(section.children || []).map((child, index) => {
const childAlias = child.alias?.value;
const isSettingsOpen = childSettingsUid === child.uid;
const childDisplayTitle =
getPageTitleByPageUid(child.text) ||
getTextByBlockUid(extractRef(child.text)) ||
child.text;
return (
<div key={child.uid}>
<div className="group flex items-center justify-between rounded bg-gray-50 p-2 hover:bg-gray-100">
<div
className="mr-2 min-w-0 flex-1 truncate"
title={child.text}
title={childDisplayTitle}
>
{childAlias ? (
<span>
<span className="font-medium">
{childAlias}
</span>
<span className="ml-2 text-xs text-gray-400">
({child.text})
({childDisplayTitle})
</span>
</span>
) : (
child.text
childDisplayTitle
)}
</div>
<ButtonGroup minimal className="flex-shrink-0">
Expand Down Expand Up @@ -439,7 +446,7 @@ const SectionItem = memo(
setChildSettingsUid(null);
refreshAndNotify();
}}
title={`Settings for "${child.text}"`}
title={`Settings for "${childDisplayTitle}"`}
style={{ width: "400px" }}
>
<div className="p-4">
Expand Down
6 changes: 6 additions & 0 deletions apps/roam/src/utils/getLeftSidebarSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export type LeftSidebarGlobalSectionConfig = {
export type LeftSidebarConfig = {
uid: string;
favoritesMigrated: BooleanSetting;
sidebarMigrated: BooleanSetting;
global: LeftSidebarGlobalSectionConfig;
personal: {
uid: string;
Expand Down Expand Up @@ -187,9 +188,14 @@ export const getLeftSidebarSettings = (
tree: leftSidebarChildren,
text: "Favorites Migrated",
});
const sidebarMigrated = getUidAndBooleanSetting({
tree: leftSidebarChildren,
text: "Sidebar Migrated",
});
return {
uid: leftSidebarUid,
favoritesMigrated,
sidebarMigrated,
global,
personal,
};
Expand Down
70 changes: 70 additions & 0 deletions apps/roam/src/utils/migrateLeftSidebarSettings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import getPageUidByPageTitle from "roamjs-components/queries/getPageUidByPageTitle";
import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageUid";
import updateBlock from "roamjs-components/writes/updateBlock";
import createBlock from "roamjs-components/writes/createBlock";
import { getFormattedConfigTree } from "./discourseConfigRef";
import { DISCOURSE_CONFIG_PAGE_TITLE } from "./renderNodeConfigPage";
import refreshConfigTree from "./refreshConfigTree";

const migrateSectionChildren = async (
children: { uid: string; text: string }[],
) => {
const promises = children.map(async (child) => {
const currentText = child.text;

const titleFromUid = getPageTitleByPageUid(currentText);
if (titleFromUid) {
return;
}

const uidFromTitle = getPageUidByPageTitle(currentText);
if (uidFromTitle) {
try {
await updateBlock({
uid: child.uid,
text: uidFromTitle,
});
console.log(
`Migrated sidebar item "${currentText}" to UID "${uidFromTitle}"`,
);
} catch (e) {
console.error(`Failed to migrate sidebar item "${currentText}"`, e);
}
}
});

await Promise.all(promises);
};

export const migrateLeftSidebarSettings = async () => {
const leftSidebarSettings = getFormattedConfigTree().leftSidebar;

if (!leftSidebarSettings.uid) return;

if (leftSidebarSettings.sidebarMigrated.value) return;

const configPageUid = getPageUidByPageTitle(DISCOURSE_CONFIG_PAGE_TITLE);
if (!configPageUid) return;

const globalChildren = leftSidebarSettings.global.children;
if (globalChildren.length > 0) {
await migrateSectionChildren(globalChildren);
}

const personalSections = leftSidebarSettings.personal.sections;
for (const section of personalSections) {
const children = section.children || [];
if (children.length > 0) {
await migrateSectionChildren(children);
}
}

if (leftSidebarSettings.uid) {
await createBlock({
parentUid: leftSidebarSettings.uid,
node: { text: "Sidebar Migrated" },
});
}

refreshConfigTree();
};