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
131 changes: 89 additions & 42 deletions apps/roam/src/components/ModifyNodeDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
Button,
Classes,
Colors,
Dialog,
Intent,
Label,
Expand All @@ -22,7 +23,9 @@ import renderOverlay, {
import fireQuery from "~/utils/fireQuery";
import getDiscourseNodes, {
excludeDefaultNodes,
type DiscourseNode,
} from "~/utils/getDiscourseNodes";
import { getAllDiscourseNodesSince } from "~/utils/getAllDiscourseNodesSince";
import FuzzySelectInput from "./FuzzySelectInput";
import { createBlock, updateBlock } from "roamjs-components/writes";
import {
Expand All @@ -40,7 +43,7 @@ import posthog from "posthog-js";
export type ModifyNodeDialogMode = "create" | "edit";
export type ModifyNodeDialogProps = {
mode: ModifyNodeDialogMode;
nodeType: string;
nodeType?: string;
initialValue: { text: string; uid: string };
initialReferencedNode?: { text: string; uid: string };
sourceBlockUid?: string; //the block that we started modifying from
Expand Down Expand Up @@ -109,13 +112,15 @@ const ModifyNodeDialog = ({
: allNodes.filter(excludeDefaultNodes);
}, [includeDefaultNodes]);

const [selectedNodeType, setSelectedNodeType] = useState(() => {
const [selectedNodeType, setSelectedNodeType] = useState<
Comment thread
trangdoan982 marked this conversation as resolved.
DiscourseNode | undefined
>(() => {
const node = discourseNodes.find((n) => n.type === nodeType);
return node || discourseNodes[0];
return node;
});

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

const referencedNode = useMemo(() => {
Expand Down Expand Up @@ -160,6 +165,19 @@ const ModifyNodeDialog = ({
if (contentRequestIdRef.current === req && alive) {
setOptions((prev) => ({ ...prev, content: results }));
}
} else {
const rawResults = await getAllDiscourseNodesSince(
undefined,
discourseNodes,
);
const results = rawResults.map((r) => ({
text: r.text,
uid: r.source_local_id,
discourseNodeType: r.type,
}));
if (contentRequestIdRef.current === req && alive) {
setOptions((prev) => ({ ...prev, content: results }));
}
}
} catch (error) {
if (contentRequestIdRef.current === req && alive) {
Expand Down Expand Up @@ -224,11 +242,24 @@ 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.discourseNodeType;
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 +335,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 +361,7 @@ const ModifyNodeDialog = ({
await addImageToPage({
pageUid,
imageUrl,
configPageUid: selectedNodeType.type,
configPageUid: selectedNodeType?.type || "",
extensionAPI,
});
}
Expand Down Expand Up @@ -373,7 +408,7 @@ const ModifyNodeDialog = ({
} else {
formattedTitle = await getNewDiscourseNodeText({
text: content.text.trim(),
nodeType: selectedNodeType.type,
nodeType: selectedNodeType!.type,
blockUid: sourceBlockUid,
});
}
Expand All @@ -384,7 +419,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,56 +540,68 @@ 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.

<Label className="w-full">
Content
<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}
/>
</Label>

{/* Node Type Selector */}
<div className="flex w-full">
<Label autoFocus={false}>
<Label autoFocus={false} className="w-full">
Node Type
<MenuItemSelect
items={discourseNodes.map((n) => n.type)}
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}
popoverProps={{ openOnTargetFocus: false }}
className={
mode === "edit" || disableNodeTypeChange
? "cursor-not-allowed opacity-50"
: ""
disabled={
mode === "edit" || disableNodeTypeChange || isContentLocked
}
popoverProps={{ openOnTargetFocus: false }}
ButtonProps={{
className:
mode === "edit" || disableNodeTypeChange || isContentLocked
? "cursor-not-allowed opacity-50"
: "",
onFocus: (e) => {
e.currentTarget.style.boxShadow = `0 0 0 2px ${Colors.BLUE3}, 0 0 0 4px ${Colors.BLUE3}4d`;
},
onBlur: (e) => {
e.currentTarget.style.boxShadow = "";
},
}}
/>
</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">
<Label>{referencedNode.name}</Label>
<Label className="w-full">
{referencedNode.name}
<FuzzySelectInput
value={referencedNodeValue}
setValue={setReferencedNodeValueCallback}
Expand All @@ -564,7 +611,7 @@ const ModifyNodeDialog = ({
isLocked={isReferencedNodeLocked}
autoFocus={false}
/>
</div>
</Label>
)}
</div>
{/* Submit Button */}
Expand Down
4 changes: 2 additions & 2 deletions apps/roam/src/utils/getAllDiscourseNodesSince.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,10 @@ export const getDiscourseNodeTypeWithSettingsBlockNodes = async (
};

export const getAllDiscourseNodesSince = async (
since: ISODateString,
since: ISODateString | undefined,
nodeTypes: DiscourseNode[],
): Promise<RoamDiscourseNodeData[]> => {
const sinceMs = new Date(since).getTime();
const sinceMs = since ? new Date(since).getTime() : 0;
if (!nodeTypes.length) {
return [];
}
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