Skip to content
15 changes: 15 additions & 0 deletions apps/roam/src/components/SuggestionsBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ import type { PageGroup } from "~/components/settings/utils/zodSchema";
import { createReifiedRelation } from "~/utils/createReifiedBlock";
import { getStoredRelationsEnabled } from "~/utils/storedRelations";
import posthog from "posthog-js";
import {
notifyBlockSuggestionAdded,
notifyRelationSuggestionAdded,
} from "~/utils/notifySuggestiveModeAdoption";

export type DiscourseData = {
results: Awaited<ReturnType<typeof getDiscourseContextResults>>;
Expand Down Expand Up @@ -360,6 +364,11 @@ const SuggestionsBody = ({
});
return;
}
try {
notifyRelationSuggestionAdded(tag, node.text);
} catch (error) {
console.error("Failed to show suggestion added notification:", error);
}
} else {
renderToast({
id: "suggestions-create-block-error",
Expand All @@ -373,7 +382,13 @@ const SuggestionsBody = ({
parentUid: blockUid,
node: { text: `[[${node.text}]]` },
});
try {
await notifyBlockSuggestionAdded(blockUid, tag, node.text);
} catch (error) {
console.error("Failed to show suggestion added notification:", error);
}
}

posthog.capture("Suggestive Mode: Suggestion Adopted", {
tag,
nodeType: node.type,
Expand Down
121 changes: 121 additions & 0 deletions apps/roam/src/utils/notifySuggestiveModeAdoption.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { render as renderToast } from "roamjs-components/components/Toast";
import getPageUidByBlockUid from "roamjs-components/queries/getPageUidByBlockUid";
import { getPersonalSetting } from "~/components/settings/utils/accessors";
import { PERSONAL_KEYS } from "~/components/settings/utils/settingKeys";
import { isPageUid } from "~/utils/isPageUid";

type RoamSidebarWindow = {
type: string;
"window-id": string;
"block-uid"?: string;
};

const showSuggestionToast = (content: string): void => {
renderToast({
id: "suggestive-mode-added",
content,
intent: "success",
timeout: 4000,
});
};

// When opening a new window, omit windowId and pass a delay to let Roam finish rendering.
const focusSidebarOutline = (windowId?: string, delayMs = 0): void => {
const focus = () => {
const container = windowId
? document.querySelector<HTMLElement>(
`[data-sidebar-window-id="${windowId}"]`,
)
: document.querySelector<HTMLElement>(".rm-sidebar-outline");
container
?.querySelector<HTMLElement>(".rm-title-display")
?.dispatchEvent(new MouseEvent("mousedown", { bubbles: true }));
};
delayMs > 0 ? setTimeout(focus, delayMs) : focus();
};

const getSidebarWindows = (): RoamSidebarWindow[] => {
try {
return window.roamAlphaAPI.ui.rightSidebar.getWindows() ?? [];
} catch {
// Sidebar API can be unavailable during Roam teardown.
return [];
}
};

const findNewWindowId = ({
before,
after,
}: {
before: RoamSidebarWindow[];
after: RoamSidebarWindow[];
}): string | undefined => {
const beforeIds = new Set(before.map((w) => w["window-id"]));
return after.find((w) => !beforeIds.has(w["window-id"]))?.["window-id"];
};

export const notifyBlockSuggestionAdded = async (
targetBlockUid: string,
sourceTitle: string,
destinationTitle: string,
): Promise<void> => {
const pageUid = isPageUid(targetBlockUid)
? targetBlockUid
: getPageUidByBlockUid(targetBlockUid) || targetBlockUid;

// getOpenPageOrBlockUid returns a page uid when a page is open, or a block uid
// when the user is zoomed into a block. Resolve either to a page uid for comparison.
const mainRawUid =
await window.roamAlphaAPI.ui.mainWindow.getOpenPageOrBlockUid();
const mainPageUid = mainRawUid
? isPageUid(mainRawUid)
? mainRawUid
: getPageUidByBlockUid(mainRawUid) || mainRawUid
: null;
const isOpenInMain = mainPageUid === pageUid;

if (
isOpenInMain ||
getPersonalSetting<boolean>([PERSONAL_KEYS.disableSidebarOpen])
) {
showSuggestionToast(
`Added relation between [[${sourceTitle}]] and [[${destinationTitle}]]`,
);
Comment on lines +81 to +83

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong toast message for block suggestions.

The toast says "Added relation between..." but this function handles block suggestions, not relation suggestions. According to the PR description, it should show: Added to [[Page Name]].

The message should reference the destination page, not both source and destination as a relation:

showSuggestionToast(
  `Added to [[${destinationTitle}]]`,
);

Currently, users adopting block suggestions see a confusing "Added relation" message even when no relation is being created.

Suggested change
showSuggestionToast(
`Added relation between [[${sourceTitle}]] and [[${destinationTitle}]]`,
);
showSuggestionToast(
`Added to [[${destinationTitle}]]`,
);

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

return;
}

const sidebarWindowsBefore = getSidebarWindows();
const existingWindow = sidebarWindowsBefore.find(
(w) =>
w.type === "outline" &&
(w["block-uid"] === targetBlockUid || w["block-uid"] === pageUid),
);

if (existingWindow) {
focusSidebarOutline(existingWindow["window-id"]);
return;
}

await window.roamAlphaAPI.ui.rightSidebar.addWindow({
window: {
// eslint-disable-next-line @typescript-eslint/naming-convention
"block-uid": pageUid,
type: "outline",
},
});

const newWindowId = findNewWindowId({
before: sidebarWindowsBefore,
after: getSidebarWindows(),
});
focusSidebarOutline(newWindowId, newWindowId ? 0 : 100);
};

export const notifyRelationSuggestionAdded = (
sourceTitle: string,
destinationTitle: string,
): void => {
showSuggestionToast(
`Added relation between [[${sourceTitle}]] and [[${destinationTitle}]]`,
);
};
Loading