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

const [selectedNodeType, setSelectedNodeType] = useState(() => {
const [selectedNodeType, setSelectedNodeType] = useState<
(typeof discourseNodes)[number] | null
>(() => {
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 @@ -158,6 +161,39 @@
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,

Check warning on line 184 in apps/roam/src/components/ModifyNodeDialog.tsx

View workflow job for this annotation

GitHub Actions / eslint (apps/roam)

[eslint (apps/roam)] apps/roam/src/components/ModifyNodeDialog.tsx#L184

Object Literal Property name `_discourseNodeType` must match one of the following formats: camelCase @typescript-eslint/naming-convention
Raw output
  184:17  warning  Object Literal Property name `_discourseNodeType` must match one of the following formats: camelCase               @typescript-eslint/naming-convention
}));
}),
);
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,9 +260,20 @@
};
}, [selectedNodeType, referencedNode]);

const setValue = useCallback((r: Result) => {
setContent(r);
}, []);
const setValue = useCallback(
(r: Result) => {
setContent(r);
if (!selectedNodeType && r.uid) {
const detectedType = (r as Record<string, unknown>)
._discourseNodeType as string | undefined;
if (detectedType) {
const nt = discourseNodes.find((n) => n.type === detectedType);
if (nt) setSelectedNodeType(nt);
}
}
},
[selectedNodeType, discourseNodes],
);

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

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 @@ -324,7 +375,7 @@
await addImageToPage({
pageUid,
imageUrl,
configPageUid: selectedNodeType.type,
configPageUid: selectedNodeType!.type,
extensionAPI,
});
}
Expand Down Expand Up @@ -371,7 +422,7 @@
} else {
formattedTitle = await getNewDiscourseNodeText({
text: content.text.trim(),
nodeType: selectedNodeType.type,
nodeType: selectedNodeType!.type,
blockUid: sourceBlockUid,
});
}
Expand All @@ -382,7 +433,7 @@
// Create new discourse node
const newPageUid = await createDiscourseNode({
text: formattedTitle,
configPageUid: selectedNodeType.type,
configPageUid: selectedNodeType!.type,
extensionAPI,
imageUrl,
});
Expand Down Expand Up @@ -503,6 +554,26 @@
style={{ pointerEvents: "all" }}
>
<div className={`${Classes.DIALOG_BODY} flex flex-col gap-4`}>
{/* Content Input */}
<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 @@ -512,38 +583,20 @@
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: "" });
}
}}
disabled={mode === "edit"}
disabled={mode === "edit" || isContentLocked}
popoverProps={{ openOnTargetFocus: false }}
/>
</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: "",
initialValue: { text: "", uid: "" },
extensionAPI,
onSuccess: async (result) => {
Expand Down
Loading