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
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import getPageTitleByPageUid from "roamjs-components/queries/getPageTitleByPageU
import renderOverlay, {
RoamOverlayProps,
} from "roamjs-components/util/renderOverlay";
import createPage from "roamjs-components/writes/createPage";
import { createBlock } from "roamjs-components/writes";
import {
insertPageRefAtRange,
snapshotInsertTarget,
Expand Down Expand Up @@ -311,6 +313,52 @@ const AdvancedNodeSearchDialog = ({
: !results.length
? "empty"
: "results";

const onOpenSearchSidebar = useCallback(async () => {
if (contentState !== "results" || !results.length) return;

try {
const sidebarBlockTitle = `Advanced search results: "${debouncedSearchTerm || "(empty query)"}"`;
const sidebarChildren = results.map((result) => ({
text: `[[${result.title}]]`,
}));

const sidebarPageUid = await createPage({ title: sidebarBlockTitle });
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reuse existing sidebar page before calling createPage

The new sidebar action always calls createPage with a deterministic title derived from the query (Advanced search results: "..."), so repeating the same search term will attempt to create the same page title again. Roam page titles are unique and createPage is not an upsert, so the second run for the same query will throw and hit the error toast instead of opening results. This makes the new Option + Enter / footer flow fail for a common repeat-search case unless you first rename/delete the previously created results page.

Useful? React with 👍 / 👎.

await Promise.all(
sidebarChildren.map((node, order) =>
createBlock({
parentUid: sidebarPageUid,
order,
node,
}),
),
);

await window.roamAlphaAPI.ui.rightSidebar.addWindow({
window: {
type: "outline",
// @ts-expect-error - block-uid is valid for outline sidebar windows
// eslint-disable-next-line @typescript-eslint/naming-convention
"block-uid": sidebarPageUid,
},
});

posthog.capture("Advanced Node Search: Open search sidebar", {
resultCount: results.length,
searchTerm: debouncedSearchTerm,
sortDirection: sort.direction,
sortField: sort.field,
});
onClose();
} catch (error) {
console.error("Failed to open search sidebar results block:", error);
renderToast({
id: "advanced-node-search-sidebar-open-error",
content: "Could not render search results in the right sidebar.",
intent: "danger",
});
}
}, [contentState, debouncedSearchTerm, onClose, results, sort]);
const handleSortChange = useCallback((nextSort: SortConfig): void => {
setSort(nextSort);
}, []);
Expand Down Expand Up @@ -349,6 +397,14 @@ const AdvancedNodeSearchDialog = ({
} else if (event.key === "ArrowUp" && results.length) {
event.preventDefault();
setActiveIndex((index) => Math.max(index - 1, 0));
} else if (
event.key === "Enter" &&
event.altKey &&
contentState === "results" &&
results.length
) {
event.preventDefault();
void onOpenSearchSidebar();
} else if (
event.key === "Enter" &&
!event.metaKey &&
Expand Down Expand Up @@ -378,6 +434,7 @@ const AdvancedNodeSearchDialog = ({
contentState,
insertTarget,
onClose,
onOpenSearchSidebar,
onInsert,
onOpen,
onOpenInSidebar,
Expand Down Expand Up @@ -481,15 +538,19 @@ const AdvancedNodeSearchDialog = ({
onInsert={() => void onInsert()}
onOpen={() => void onOpen()}
onOpenInSidebar={() => void onOpenInSidebar()}
onOpenSearchSidebar={() => void onOpenSearchSidebar()}
/>
</div>
</Dialog>
);
};

export const renderAdvancedNodeSearchDialog = () =>
export const renderAdvancedNodeSearchSidebar = () =>
renderOverlay({
// eslint-disable-next-line @typescript-eslint/naming-convention
Overlay: AdvancedNodeSearchDialog,
props: {},
});

export const renderAdvancedNodeSearchDialog = () =>
renderAdvancedNodeSearchSidebar();
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type AdvancedSearchFooterProps = {
onInsert: () => void;
onOpen: () => void;
onOpenInSidebar: () => void;
onOpenSearchSidebar: () => void;
};

const footerKbdClassName =
Expand Down Expand Up @@ -99,6 +100,21 @@ const InsertFooterAction = ({
/>
);

export const OpenSearchSidebarFooterAction = ({
disabled,
onOpenSearchSidebar,
}: {
disabled: boolean;
onOpenSearchSidebar: () => void;
}) => (
<FooterShortcutHint
disabled={disabled}
keyIcons={["key-option", "key-enter"]}
label="open search sidebar"
onClick={() => void onOpenSearchSidebar()}
/>
);

const CloseFooterHint = () => (
<span className={footerLabelClassName}>
<kbd className={footerKbdClassName}>
Expand All @@ -115,14 +131,20 @@ export const AdvancedSearchFooter = ({
onInsert,
onOpen,
onOpenInSidebar,
onOpenSearchSidebar,
}: AdvancedSearchFooterProps) => {
const hasResults = contentState === "results";
const canOpen = hasActiveResult && hasResults;
const canInsert = !!insertTarget && hasActiveResult && hasResults;
const canOpenSearchSidebar = hasResults;

return (
<div className="flex w-full flex-none items-center justify-between border-t border-gray-200 bg-gray-50 px-3 py-2">
<div className="inline-flex shrink-0 items-center gap-3">
<OpenSearchSidebarFooterAction
disabled={!canOpenSearchSidebar}
onOpenSearchSidebar={onOpenSearchSidebar}
/>
{insertTarget && (
<InsertFooterAction disabled={!canInsert} onInsert={onInsert} />
)}
Expand Down
Loading