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
125 changes: 92 additions & 33 deletions apps/roam/src/components/ModifyNodeDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,16 @@ const ModifyNodeDialog = ({
: allNodes.filter(excludeDefaultNodes);
}, [includeDefaultNodes]);

const [selectedNodeType, setSelectedNodeType] = useState(() => {
const [selectedNodeType, setSelectedNodeType] = useState<
(typeof discourseNodes)[number] | null
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

>(() => {
if (!nodeType) return null;
const node = discourseNodes.find((n) => n.type === nodeType);
return node || discourseNodes[0];
return node || null;
});

const nodeFormat = useMemo(() => {
return selectedNodeType.format || "";
return selectedNodeType?.format || "";
}, [selectedNodeType]);

const referencedNode = useMemo(() => {
Expand Down Expand Up @@ -160,6 +163,39 @@ const ModifyNodeDialog = ({
if (contentRequestIdRef.current === req && alive) {
setOptions((prev) => ({ ...prev, content: results }));
}
} else {
// Query all discourse node types in parallel
const allResults = await Promise.all(
discourseNodes.map(async (node) => {
const conditionUid = window.roamAlphaAPI.util.generateUID();
const results = await fireQuery({
returnNode: "node",
selections: [],
conditions: [
{
source: "node",
relation: "is a",
target: node.type,
uid: conditionUid,
type: "clause",
},
],
});
return results.map((r) => ({
...r,
discourseNodeType: node.type,
}));
}),
);
const seen = new Set<string>();
const deduped = allResults.flat().filter((r) => {
if (seen.has(r.uid)) return false;
seen.add(r.uid);
return true;
});
if (contentRequestIdRef.current === req && alive) {
setOptions((prev) => ({ ...prev, content: deduped }));
}
}
} catch (error) {
if (contentRequestIdRef.current === req && alive) {
Expand Down Expand Up @@ -224,11 +260,25 @@ const ModifyNodeDialog = ({
alive = false;
refAlive = false;
};
}, [selectedNodeType, referencedNode]);

const setValue = useCallback((r: Result) => {
setContent(r);
}, []);
}, [selectedNodeType, referencedNode, discourseNodes]);

const setValue = useCallback(
(r: Result) => {
setContent(r);
if (!selectedNodeType && r.uid) {
const detectedType = (r as Record<string, unknown>)
.discourseNodeType as string | undefined;
if (detectedType) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

const nt = discourseNodes.find((n) => n.type === detectedType);
if (nt) {
setSelectedNodeType(nt);
setError("");
}
}
}
},
[selectedNodeType, discourseNodes],
);

const setReferencedNodeValueCallback = useCallback((r: Result) => {
setReferencedNodeValue(r);
Expand Down Expand Up @@ -304,9 +354,13 @@ const ModifyNodeDialog = ({

const onSubmit = async () => {
if (!content.text.trim()) return;
if (!selectedNodeType && !isContentLocked) {
setError("Please select a node type");
return;
}
posthog.capture("Modify Node Dialog: Submit Triggered", {
mode,
nodeType: selectedNodeType.type,
nodeType: selectedNodeType?.type,
});
try {
if (mode === "create") {
Expand All @@ -326,7 +380,7 @@ const ModifyNodeDialog = ({
await addImageToPage({
pageUid,
imageUrl,
configPageUid: selectedNodeType.type,
configPageUid: selectedNodeType?.type || "",
extensionAPI,
});
}
Expand Down Expand Up @@ -373,7 +427,7 @@ const ModifyNodeDialog = ({
} else {
formattedTitle = await getNewDiscourseNodeText({
text: content.text.trim(),
nodeType: selectedNodeType.type,
nodeType: selectedNodeType!.type,
blockUid: sourceBlockUid,
});
}
Expand All @@ -384,7 +438,7 @@ const ModifyNodeDialog = ({
// Create new discourse node
const newPageUid = await createDiscourseNode({
text: formattedTitle,
configPageUid: selectedNodeType.type,
configPageUid: selectedNodeType!.type,
extensionAPI,
imageUrl,
});
Expand Down Expand Up @@ -505,6 +559,26 @@ const ModifyNodeDialog = ({
style={{ pointerEvents: "all" }}
>
<div className={`${Classes.DIALOG_BODY} flex flex-col gap-4`}>
{/* Content Input */}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

<div className="w-full">
<Label>Content</Label>
<FuzzySelectInput
value={content}
setValue={setValue}
options={options.content}
placeholder={
loading
? "..."
: selectedNodeType
? `Enter a ${selectedNodeType.text.toLowerCase()} ...`
: "Search all nodes..."
}
mode={mode}
isLocked={isContentLocked}
autoFocus={!isContentLocked}
/>
</div>

{/* Node Type Selector */}
<div className="flex w-full">
<Label autoFocus={false}>
Expand All @@ -514,43 +588,28 @@ const ModifyNodeDialog = ({
transformItem={(t) =>
discourseNodes.find((n) => n.type === t)?.text || t
}
activeItem={selectedNodeType.type}
activeItem={selectedNodeType?.type ?? null}
onItemSelect={(t) => {
const nt = discourseNodes.find((n) => n.type === t);
if (nt) {
setSelectedNodeType(nt);
setReferencedNodeValue({ text: "", uid: "" });
setError("");
}
}}
disabled={mode === "edit" || disableNodeTypeChange}
disabled={
mode === "edit" || disableNodeTypeChange || isContentLocked
}
popoverProps={{ openOnTargetFocus: false }}
className={
mode === "edit" || disableNodeTypeChange
mode === "edit" || disableNodeTypeChange || isContentLocked
? "cursor-not-allowed opacity-50"
: ""
}
/>
</Label>
</div>

{/* Content Input */}
<div className="w-full">
<Label>Content</Label>
<FuzzySelectInput
value={content}
setValue={setValue}
options={options.content}
placeholder={
loading
? "..."
: `Enter a ${selectedNodeType.text.toLowerCase()} ...`
}
mode={mode}
isLocked={isContentLocked}
autoFocus={!isContentLocked}
/>
</div>

{/* Referenced Node Input */}
{referencedNode && !isContentLocked && mode === "create" && (
<div className="w-full">
Expand Down
12 changes: 1 addition & 11 deletions apps/roam/src/utils/registerCommandPaletteCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,19 +189,9 @@ export const registerCommandPaletteCommands = (onloadArgs: OnloadArgs) => {

const selectionStart = uid ? getSelectionStartForBlock(uid) : 0;

const defaultNodeType =
getDiscourseNodes().filter(excludeDefaultNodes)[0]?.type;
if (!defaultNodeType) {
renderToast({
id: "create-discourse-node-command-no-types",
content: "No discourse node types found in settings.",
});
return;
}

renderModifyNodeDialog({
mode: "create",
nodeType: defaultNodeType,
nodeType: "",
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

initialValue: { text: "", uid: "" },
extensionAPI,
onSuccess: async (result) => {
Expand Down
Loading