Skip to content

Conversation

@trangdoan982
Copy link
Collaborator

@trangdoan982 trangdoan982 commented Nov 12, 2025

In node tag
https://www.loom.com/share/efccc26071d640c484858c9b9fc93ad2

In Canvas:
https://www.loom.com/share/da0df074fb264dc690acfb36c0bc07c8

In command
https://www.loom.com/share/a94cd3802e0f43f39f94ff65e4979dcd

Summary by CodeRabbit

  • New Features

    • Added improved dialog interface for creating and editing discourse nodes with enhanced workflow
    • Introduced fuzzy-search select input for better item discovery and selection
    • Added value locking capability during node creation process
  • Chores

    • Updated roamjs-components dependency to 0.85.6

@linear
Copy link

linear bot commented Nov 12, 2025

@supabase
Copy link

supabase bot commented Nov 12, 2025

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@trangdoan982
Copy link
Collaborator Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 12, 2025

✅ Actions performed

Full review triggered.

"react-in-viewport": "1.0.0-alpha.20",
"react-vertical-timeline-component": "3.5.2",
"roamjs-components": "0.85.4",
"roamjs-components": "0.85.6",
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

i left these changes here after trying out the autoSelectFirstOption props because I think we should upgrade roamjs-compoenents anyway

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 12, 2025

📝 Walkthrough

Walkthrough

This PR introduces a new ModifyNodeDialog component to replace the deprecated CreateNodeDialog, adding fuzzy-search and lockable input components for node creation/editing. Related utilities and canvas integrations are updated to use the new dialog, and a dependency is bumped.

Changes

Cohort / File(s) Summary
Dependency Update
apps/roam/package.json
Bumps roamjs-components from 0.85.4 to 0.85.6.
Deprecation Notice
apps/roam/src/components/CreateNodeDialog.tsx
Adds deprecation header guiding migration to ModifyNodeDialog with API mapping notes.
New Input Components
apps/roam/src/components/FuzzySelectInput.tsx, apps/roam/src/components/LockableAutocompleteInput.tsx
Introduces FuzzySelectInput with fuzzy-search filtering and create/edit modes. Introduces LockableAutocompleteInput extending AutocompleteInput with locking behavior for selected options. Both support keyboard navigation, value locking, and mode-dependent rendering.
New Dialog Component
apps/roam/src/components/ModifyNodeDialog.tsx
Adds ModifyNodeDialog modal for creating/editing discourse nodes with node type selection, FuzzySelectInput for content, optional referenced node input, asynchronous data loading, and node creation/editing flows with success toasts. Exports ModidfyNodeDialogMode, ModifyNodeDialogProps, and renderModifyNodeDialog helper.
Canvas Integration
apps/roam/src/components/canvas/DiscourseNodeUtil.tsx
Replaces LabelDialog editing flow with renderModifyNodeDialog. Introduces dialogRendered state, updates onSuccess handler to refresh node props and optionally create canvas relations.
Format Utilities
apps/roam/src/utils/formatUtils.ts
Updates renderFormDialog to use ModifyNodeDialog instead of FormDialog. Refactors getNewDiscourseNodeText to invoke ModifyNodeDialog in create mode with nodeType and initialValue, resolving only on valid onSuccess results.
Node Tag Popup
apps/roam/src/utils/renderNodeTagPopup.tsx
Replaces renderCreateNodeDialog call with renderModifyNodeDialog in onClick handler. Updates payload to include mode: "create" and initialReferencedNode; introduces local getInitialReferencedNode helper.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Canvas as DiscourseNodeUtil
    participant Dialog as ModifyNodeDialog
    participant API as Roam API
    participant Toast as Toast Notifications

    User->>Canvas: Double-click node (edit mode)
    Canvas->>Canvas: Set editing=true, dialogRendered=true
    Canvas->>Dialog: renderModifyNodeDialog({mode: "edit", ...})
    Dialog->>API: Fetch node types, content options
    API-->>Dialog: Node types, content loaded
    User->>Dialog: Select content / referenced node
    User->>Dialog: Click Confirm
    Dialog->>API: updateBlock(sourceBlockUid, newText)
    API-->>Dialog: Update complete
    Dialog->>Canvas: onSuccess(result)
    Canvas->>API: Update node title, uid, image
    Canvas->>Toast: Show success notification
    Canvas->>Canvas: Set editing=false, dialogRendered=false
    Dialog-->>User: Close dialog
Loading
sequenceDiagram
    actor User
    participant Popup as renderNodeTagPopup
    participant Dialog as ModifyNodeDialog
    participant API as Roam API

    User->>Popup: Click create node trigger
    Popup->>Popup: Get initialReferencedNode
    Popup->>Dialog: renderModifyNodeDialog({mode: "create", initialValue, ...})
    Dialog->>API: Fetch node types and content options
    API-->>Dialog: Options loaded
    User->>Dialog: Select node type
    Dialog->>Dialog: Update content input options
    User->>Dialog: Select/lock content
    User->>Dialog: Click Confirm
    Dialog->>API: fireQuery(createDiscourseNode)
    API-->>Dialog: New node created
    Dialog->>API: updateBlock(sourceBlockUid, newText)
    API-->>Dialog: Source block updated
    Dialog-->>User: Close with success
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • FuzzySelectInput.tsx and LockableAutocompleteInput.tsx: Review keyboard navigation logic, state management for lock/dropdown visibility, and fuzzy-search integration.
  • ModifyNodeDialog.tsx: Review asynchronous data loading with cancellation safety, node creation/editing logic, error handling, and the onSuccess callback flow; verify API integrations with fireQuery, createDiscourseNode, updateBlock, createBlock.
  • DiscourseNodeUtil.tsx: Verify dialog lifecycle management tied to editing state and shape prop updates in onSuccess; check canvas relation creation logic.
  • Integration points (formatUtils.ts, renderNodeTagPopup.tsx): Ensure payload transformation and mode handling are consistent across call sites.

Possibly related PRs

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title '[ENG-979] Consolidate create node flow' accurately describes the main objective of the changeset, which consolidates multiple node creation flows into a unified ModifyNodeDialog component used across multiple files.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/roam/src/utils/formatUtils.ts (1)

64-91: Remove redundant DOM manipulation code.

The setupButtonControl function manipulates the dialog's DOM to enable/disable the submit button based on input. However, ModifyNodeDialog already handles this internally (line 481 disables the button when !contentText.trim()). This code is redundant and could cause issues if the dialog's DOM structure changes.

Apply this diff to remove the obsolete code:

       });

-      const setupButtonControl = () => {
-        const dialogs = document.querySelectorAll(".bp3-dialog");
-        const dialog = dialogs[dialogs.length - 1] as HTMLElement;
-
-        const input = dialog.querySelector(
-          'input[type="text"].bp3-input',
-        ) as HTMLInputElement;
-        const submitBtn = dialog.querySelector(
-          ".bp3-dialog-footer .bp3-button.bp3-intent-primary",
-        ) as HTMLButtonElement;
-
-        const updateButtonState = () => {
-          const currentValue = input.value;
-          const hasValue = currentValue.trim().length > 0;
-          const shouldBeDisabled = !hasValue;
-          submitBtn.disabled = shouldBeDisabled;
-        };
-
-        updateButtonState();
-
-        const listenerKey = "_discourseNodeListenerAttached";
-        if (!(input as any)[listenerKey]) {
-          input.addEventListener("input", updateButtonState);
-          (input as any)[listenerKey] = true;
-        }
-      };
-      requestAnimationFrame(setupButtonControl);
     });
🧹 Nitpick comments (2)
apps/roam/src/components/LockableAutocompleteInput.tsx (1)

34-37: Remove debug logging from production code.

The console.log calls will fire on every selection and clutter the console. Please drop these before merging.

Apply this cleanup:

-        console.log("locking value", q);
-        console.log("initialUid", initialUid);
-        console.log("q.uid", q.uid);
-        console.log("mode", mode);
apps/roam/src/utils/renderNodeTagPopup.tsx (1)

45-48: Track the TODO for initialReferencedNode implementation.

The placeholder implementation returns empty values. Ensure this TODO is tracked in your issue tracker to implement proper referenced node detection from the block context.

Would you like me to open a new issue to track this implementation task?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de69756 and a050f77.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • apps/roam/package.json (2 hunks)
  • apps/roam/src/components/CreateNodeDialog.tsx (1 hunks)
  • apps/roam/src/components/FuzzySelectInput.tsx (1 hunks)
  • apps/roam/src/components/LockableAutocompleteInput.tsx (1 hunks)
  • apps/roam/src/components/ModifyNodeDialog.tsx (1 hunks)
  • apps/roam/src/components/canvas/DiscourseNodeUtil.tsx (3 hunks)
  • apps/roam/src/utils/formatUtils.ts (2 hunks)
  • apps/roam/src/utils/renderNodeTagPopup.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx}: Prefer type over interface
Use explicit return types for functions
Avoid any types when possible

Files:

  • apps/roam/src/components/FuzzySelectInput.tsx
  • apps/roam/src/components/CreateNodeDialog.tsx
  • apps/roam/src/components/LockableAutocompleteInput.tsx
  • apps/roam/src/utils/formatUtils.ts
  • apps/roam/src/components/ModifyNodeDialog.tsx
  • apps/roam/src/utils/renderNodeTagPopup.tsx
  • apps/roam/src/components/canvas/DiscourseNodeUtil.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/main.mdc)

**/*.{ts,tsx,js,jsx}: Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use Prettier with the project's configuration
Maintain consistent naming conventions: PascalCase for components and types
Maintain consistent naming conventions: camelCase for variables and functions
Maintain consistent naming conventions: UPPERCASE for constants

Files:

  • apps/roam/src/components/FuzzySelectInput.tsx
  • apps/roam/src/components/CreateNodeDialog.tsx
  • apps/roam/src/components/LockableAutocompleteInput.tsx
  • apps/roam/src/utils/formatUtils.ts
  • apps/roam/src/components/ModifyNodeDialog.tsx
  • apps/roam/src/utils/renderNodeTagPopup.tsx
  • apps/roam/src/components/canvas/DiscourseNodeUtil.tsx
apps/roam/**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

apps/roam/**/*.{js,jsx,ts,tsx}: Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension
Use the roamAlphaApi documentation from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when working with the Roam API
Use Roam Depot/Extension API documentation from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when working with the Roam Extension API

Files:

  • apps/roam/src/components/FuzzySelectInput.tsx
  • apps/roam/src/components/CreateNodeDialog.tsx
  • apps/roam/src/components/LockableAutocompleteInput.tsx
  • apps/roam/src/utils/formatUtils.ts
  • apps/roam/src/components/ModifyNodeDialog.tsx
  • apps/roam/src/utils/renderNodeTagPopup.tsx
  • apps/roam/src/components/canvas/DiscourseNodeUtil.tsx
apps/roam/package.json

📄 CodeRabbit inference engine (.cursor/rules/roam.mdc)

Prefer existing dependencies from package.json when adding or using dependencies in the Roam Research extension

Files:

  • apps/roam/package.json
🧠 Learnings (11)
📚 Learning: 2025-07-19T22:34:23.619Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-07-19T22:34:23.619Z
Learning: Applies to apps/roam/**/*.{js,jsx,ts,tsx} : Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Applied to files:

  • apps/roam/src/components/FuzzySelectInput.tsx
  • apps/roam/src/components/LockableAutocompleteInput.tsx
  • apps/roam/package.json
  • apps/roam/src/components/ModifyNodeDialog.tsx
📚 Learning: 2025-07-19T22:34:08.725Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/main.mdc:0-0
Timestamp: 2025-07-19T22:34:08.725Z
Learning: Applies to {apps/website,packages/ui}/**/*.{tsx,jsx} : Use platform-native UI components first with shadcn/ui as a fallback

Applied to files:

  • apps/roam/src/components/FuzzySelectInput.tsx
📚 Learning: 2025-07-19T22:34:23.619Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-07-19T22:34:23.619Z
Learning: Applies to apps/roam/**/*.{js,jsx,ts,tsx} : Use Roam Depot/Extension API documentation from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when working with the Roam Extension API

Applied to files:

  • apps/roam/src/components/CreateNodeDialog.tsx
  • apps/roam/package.json
📚 Learning: 2025-08-11T19:09:58.252Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 337
File: apps/roam/src/components/DiscourseFloatingMenu.tsx:43-43
Timestamp: 2025-08-11T19:09:58.252Z
Learning: The roam subdirectory (apps/roam) is constrained to React 17 and cannot use React 18+ features like createRoot API. ReactDOM.render should be used instead of createRoot in this subdirectory.

Applied to files:

  • apps/roam/src/components/CreateNodeDialog.tsx
  • apps/roam/package.json
📚 Learning: 2025-07-19T22:34:23.619Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-07-19T22:34:23.619Z
Learning: Applies to apps/roam/**/*.{js,jsx,ts,tsx} : Use the roamAlphaApi documentation from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when working with the Roam API

Applied to files:

  • apps/roam/src/components/CreateNodeDialog.tsx
  • apps/roam/package.json
  • apps/roam/src/components/ModifyNodeDialog.tsx
  • apps/roam/src/utils/renderNodeTagPopup.tsx
📚 Learning: 2025-07-19T22:34:23.619Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-07-19T22:34:23.619Z
Learning: Applies to apps/roam/package.json : Prefer existing dependencies from package.json when adding or using dependencies in the Roam Research extension

Applied to files:

  • apps/roam/package.json
📚 Learning: 2025-07-19T22:34:16.794Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/obsidian.mdc:0-0
Timestamp: 2025-07-19T22:34:16.794Z
Learning: Applies to apps/obsidian/package.json : Prefer existing dependencies from package.json when adding or using dependencies in the Obsidian plugin

Applied to files:

  • apps/roam/package.json
📚 Learning: 2025-06-22T10:40:52.752Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

Applied to files:

  • apps/roam/src/utils/formatUtils.ts
  • apps/roam/src/components/canvas/DiscourseNodeUtil.tsx
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `type` serves as the unique identifier field, not a type classification field. The interface has no `uid` or `id` field, making `node.type` the correct field to use for UID-related operations.

Applied to files:

  • apps/roam/src/utils/formatUtils.ts
📚 Learning: 2025-06-17T23:37:45.289Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `node.type` serves as the UID field rather than having a conventional `node.uid` field. This is an unusual naming convention where the type field actually contains the unique identifier.

Applied to files:

  • apps/roam/src/utils/formatUtils.ts
  • apps/roam/src/components/ModifyNodeDialog.tsx
📚 Learning: 2025-08-25T15:53:21.799Z
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 372
File: apps/roam/src/components/DiscourseNodeMenu.tsx:116-116
Timestamp: 2025-08-25T15:53:21.799Z
Learning: In apps/roam/src/components/DiscourseNodeMenu.tsx, when handling tag insertion, multiple leading hashtags (like ##foo) should be preserved as they represent user intent, not normalized to a single hashtag. The current regex /^#/ is correct as it only removes one leading # before adding one back, maintaining any additional hashtags the user intended.

Applied to files:

  • apps/roam/src/components/ModifyNodeDialog.tsx
  • apps/roam/src/utils/renderNodeTagPopup.tsx
🔇 Additional comments (12)
apps/roam/src/utils/formatUtils.ts (2)

15-18: LGTM: Clean import addition.

The new imports for ModifyNodeDialog and related types are well-organized and follow the project's import conventions.


20-23: LGTM: Type parameter correctly updated.

The generic type parameter change from FormDialogProps to ModifyNodeDialogProps properly reflects the migration to the new dialog component.

apps/roam/src/utils/renderNodeTagPopup.tsx (2)

8-8: LGTM: Import updated correctly.

The import change from the old dialog to renderModifyNodeDialog aligns with the consolidation objective.


57-70: ****

The no-op callbacks are intentional and appropriate. This function renders a simple UI button that triggers dialog-driven node creation—it doesn't manage node state or handle post-creation logic. The ModifyNodeDialog component itself handles creation, persistence, and cleanup. Unlike other call sites (e.g., DiscourseNodeUtil.tsx) where the parent needs to track the created node's UID for state updates, renderNodeTagPopupButton has no such responsibility. The comment "Success is handled by the dialog itself" accurately reflects this design.

Likely an incorrect or invalid review comment.

apps/roam/src/components/ModifyNodeDialog.tsx (8)

1-33: LGTM: Comprehensive imports.

The imports are well-organized and include all necessary dependencies for the dialog functionality.


52-97: LGTM: Well-structured component initialization.

The component uses appropriate React hooks with proper initialization and memoization. The filtering logic for discourse nodes based on isFromCanvas is clear and well-documented.


98-124: LGTM: Robust referenced node detection.

The logic correctly parses the node format string to extract referenced node information, with proper filtering of special cases like "content" and "context".


126-202: LGTM: Excellent async race condition handling.

The use of request IDs and alive flags properly handles race conditions when fetching options. The cleanup function ensures no state updates occur after unmounting.


239-391: LGTM: Comprehensive create and edit logic.

The submission logic handles both create and edit modes appropriately, with proper error handling, loading state management, and user feedback via toasts. The locked content flow is handled correctly.


393-497: LGTM: Well-structured dialog UI.

The component follows BlueprintJS patterns correctly, with proper event handling to prevent TLDraw interference, appropriate disabled states, and clear error messaging.

As per coding guidelines


499-505: LGTM: Standard overlay render pattern.

The helper function and default export follow established patterns in the codebase.


320-328: Fix invalid type value; remove incorrect error suppression.

The @ts-expect-error suppression on "block-uid" is misplaced. According to the Roam API type definition, "block-uid" is a valid optional property. The actual TypeScript error is caused by type: "outline", which is invalid. The valid type values are "block" | "page" | "query" | "graph" | "search".

Fix: Replace type: "outline" with a valid type value (e.g., "block"), or adjust the window configuration to match the intended functionality. Remove the @ts-expect-error suppression.

⛔ Skipped due to learnings
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 0
File: :0-0
Timestamp: 2025-11-06T13:48:35.007Z
Learning: In apps/roam/src/utils/createReifiedBlock.ts, the `setBlockProps` function does not need await as it is synchronous or fire-and-forget.
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 220
File: apps/roam/src/utils/conceptConversion.ts:42-56
Timestamp: 2025-06-17T23:37:45.289Z
Learning: In the DiscourseNode interface from apps/roam/src/utils/getDiscourseNodes.ts, the field `type` serves as the unique identifier field, not a type classification field. The interface has no `uid` or `id` field, making `node.type` the correct field to use for UID-related operations.
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-07-19T22:34:23.619Z
Learning: Applies to apps/roam/**/*.{js,jsx,ts,tsx} : Use the roamAlphaApi documentation from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when working with the Roam API

Comment on lines 204 to 223
useEffect(() => {
if (mode === "edit" && referencedNode) {
setReferencedNodeLoading(true);
// TODO: replace this with a regex. this is extremely hacky primitive
const parseResult = contentText.trim().split("-");
if (parseResult) {
// parseResult[1] is content, parseResult[2] is refnode
if (parseResult[1]) {
setContentText(parseResult[1].trim());
}
if (parseResult[2]) {
const refText = parseResult[2].trim().replace(/[[\]]/g, "");
setReferencedNodeText(refText);
const result = getPageUidByPageTitle(refText);
setReferencedNodeUid(result);
}
}
}
setReferencedNodeLoading(false);
}, [mode, referencedNode, nodeFormat, contentText]);
Copy link
Contributor

@coderabbitai coderabbitai bot Nov 12, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Fragile parsing logic needs improvement.

The comment on line 207 correctly identifies this as "extremely hacky primitive" parsing. Splitting on "-" is fragile and will break if the content contains hyphens. The regex mentioned in the TODO would be more robust.

Consider using the nodeFormat pattern to parse the content more reliably:

useEffect(() => {
  if (mode === "edit" && referencedNode) {
    setReferencedNodeLoading(true);
    
    // Use the nodeFormat to extract content and referenced node
    const regex = new RegExp(
      nodeFormat
        .replace(/{content}/gi, '(.+?)')
        .replace(/{[\w\d-]+}/g, '\\[\\[(.+?)\\]\\]')
        .replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&')
    );
    
    const match = contentText.match(regex);
    if (match) {
      setContentText(match[1]?.trim() || "");
      if (match[2]) {
        const refText = match[2].trim();
        setReferencedNodeText(refText);
        const result = getPageUidByPageTitle(refText);
        setReferencedNodeUid(result);
      }
    }
  }
  setReferencedNodeLoading(false);
}, [mode, referencedNode, nodeFormat, contentText]);
🤖 Prompt for AI Agents
In apps/roam/src/components/ModifyNodeDialog.tsx around lines 204 to 223, the
current split-on-hyphen parsing is fragile; replace it with a regex derived from
nodeFormat: escape regex metacharacters, replace {content} with a non-greedy
capture group (e.g. (.+?)), replace reference placeholders with a capture for
the inner page title and literal double-bracket markers (e.g. \[\[(.+?)\]\]),
then run contentText.match(regex) and if there is a match
setContentText(match[1]?.trim() || "") and, if present,
setReferencedNodeText(match[2].trim()) and
setReferencedNodeUid(getPageUidByPageTitle(match[2].trim())); keep the
referencedNodeLoading toggles around the parse and ensure you don’t rely on
brittle string splitting.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

the regex needs to be more complex I'll follow up with another ticket that address this issue + also auto detecting Source/ RefNode when created from tagged block of child node

Copy link
Contributor

Choose a reason for hiding this comment

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

@trangdoan982, sounds good! That makes sense to address this along with the auto-detection feature in a follow-up.

Would you like me to create a GitHub issue to track this work? I can include:

  • The parsing logic improvement (replacing the split-on-hyphen with proper regex)
  • Auto-detecting Source/RefNode when created from tagged block or child node
  • Links back to this PR and comment for context

🧠 Learnings used
Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:18-31
Timestamp: 2025-06-22T10:40:52.752Z
Learning: In apps/roam/src/utils/getAllDiscourseNodesSince.ts, the user confirmed that querying for `?title` with `:node/title` and mapping it to the `text` field in the DiscourseGraphContent type is the correct implementation for retrieving discourse node content from Roam Research, despite it appearing to query page titles rather than block text content.

Learnt from: sid597
Repo: DiscourseGraphs/discourse-graph PR: 372
File: apps/roam/src/components/DiscourseNodeMenu.tsx:116-116
Timestamp: 2025-08-25T15:53:21.799Z
Learning: In apps/roam/src/components/DiscourseNodeMenu.tsx, when handling tag insertion, multiple leading hashtags (like ##foo) should be preserved as they represent user intent, not normalized to a single hashtag. The current regex /^#/ is correct as it only removes one leading # before adding one back, maintaining any additional hashtags the user intended.

@trangdoan982 trangdoan982 changed the title [ENG-979]0 Consolidate create node flow [ENG-979] Consolidate create node flow Nov 19, 2025
@trangdoan982
Copy link
Collaborator Author

next action: rebase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

No open projects
Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants