Skip to content

Conversation

@mdroidian
Copy link
Contributor

@mdroidian mdroidian commented Jan 5, 2026

https://www.loom.com/share/9b391029e9cf453eb728fb0fc72467e9

Summary by CodeRabbit

  • Bug Fixes

    • Improved export reliability with guarded updates and explicit success/failure signaling when sending canvases.
    • Added user notification and abort behavior when attempting to export legacy/unsupported canvas formats.
  • Refactor

    • Reworked export flow to use a structured canvas store lifecycle and migrations for more consistent, predictable exports.
    • Exposed format-detection to better handle modern vs legacy canvases.

✏️ Tip: You can customize this high-level summary in your review settings.

…mprove canvas integration

- Updated addToSelectedCanvas function to handle both legacy and new TLStore formats.
- Introduced utility functions for managing discourse relations and nodes.
- Enhanced error handling for canvas updates.
- Export dialog now correctly updates the store schema and state.
@linear
Copy link

linear bot commented Jan 5, 2026

@supabase
Copy link

supabase bot commented Jan 5, 2026

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 ↗︎.

@mdroidian
Copy link
Contributor Author

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

📝 Walkthrough

Walkthrough

Restructures the Export flow to use TLStoreSnapshot-based store management for TLDraw content, detects and aborts on legacy stores, initializes/migrates TLStore snapshots for new canvases, performs shape operations against the snapshot store, and adds guarded Roam block updates that return explicit success/failure.

Changes

Cohort / File(s) Summary
Export flow & TLStoreSnapshot integration
apps/roam/src/components/Export.tsx
Replaces legacy mutable store handling with TLStoreSnapshot-based lifecycle: detects snapshot vs legacy, initializes/migrates/loads TLStore, performs shape creation/placement against tlStoreSnapshot.store, extracts page key from serialized store, computes bounds, and wraps window.roamAlphaAPI.updateBlock in try/catch to return boolean success. Adds legacy-format toast and abort path.
Type guard export
apps/roam/src/components/canvas/useRoamStore.ts
Exports isTLStoreSnapshot type guard from the module (no logic change).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Export
    participant TLStoreUtils as "TLStore Utils"
    participant RoamAPI as "Roam API"

    User->>Export: Start export/send to canvas
    Export->>TLStoreUtils: Inspect input -> isTLStoreSnapshot?
    alt Legacy store detected
        Export->>User: Show legacy-format toast & abort
    else TLStoreSnapshot or new canvas
        Export->>TLStoreUtils: Initialize/create/migrate TLStoreSnapshot
        TLStoreUtils-->>Export: tlStoreSnapshot ready
        rect rgb(220, 240, 220)
            note right of Export: Create/place shapes against tlStoreSnapshot.store
            Export->>Export: Add discourse shapes, compute bounds, getPageKey
            Export->>TLStoreUtils: loadSnapshot/commit changes
        end
        rect rgb(220, 220, 240)
            note right of Export: Update Roam block with tldraw store/schema
            Export->>RoamAPI: updateBlock(...)
            alt updateBlock succeeds
                RoamAPI-->>Export: success
                Export-->>User: return true
            else updateBlock fails
                RoamAPI-->>Export: error
                Export->>Export: log internalError
                Export-->>User: return false
            end
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

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.
Title check ✅ Passed The title references ENG-952 ticket and the core issue (inconsistent send nodes to canvas behavior), directly matching the PR's refactoring of export flow to use TLStoreSnapshot-based management.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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: 1

Fix all issues with AI Agents 🤖
In @apps/roam/src/components/Export.tsx:
- Around line 425-442: The early exits in Export.tsx currently use "return
console.log(...)" which returns undefined; change these to return a boolean
(e.g., log then "return false") so the function's callers (like handleSendTo)
receive a consistent boolean result. Specifically, replace the two occurrences
around the tlStoreSnapshot check and the pageKey check (the block defining
getPageKey and the subsequent pageKey usage) to call console.log(...) or process
the log first and then "return false" to signal failure.
🧹 Nitpick comments (4)
apps/roam/src/components/Export.tsx (4)

267-303: Simplify legacy store detection.

The isLegacyStore check has redundant conditions since tldraw is already defaulted to {} on line 265, making the null/undefined checks unnecessary.

🔎 Suggested simplification
-    const isLegacyStore =
-      !isTLStore &&
-      tldraw !== null &&
-      tldraw !== undefined &&
-      typeof tldraw === "object" &&
-      Object.keys(tldraw).length !== 0;
+    const isLegacyStore = !isTLStore && Object.keys(tldraw).length !== 0;

416-418: Avoid mutating the input object.

Line 416 mutates tldraw.schema directly on what may be the original object from blockProps. While this works in the !isTLStore branch (where tldraw is a fresh empty object or copy), consider assigning to a local variable to make the intent clearer and avoid potential side effects if the upstream data structure changes.

🔎 Suggested refactor

The mutation is safe here since tldraw defaults to {} when not a TLStoreSnapshot, but the pattern could be cleaner:

-      tldraw.schema = tlStore.schema.serialize();
-      tempTlStoreSnapshot = tlStore.getStoreSnapshot();
+      tempTlStoreSnapshot = tlStore.getStoreSnapshot();

Since tempTlStoreSnapshot already contains the schema from getStoreSnapshot(), the explicit schema assignment is redundant.


574-587: Consider limiting error context size.

The error context includes the full results array and blockProps, which could be large and cause issues with error logging/reporting systems. Consider limiting to a sample or summary.

🔎 Suggested improvement
       internalError({
         error: error as Error,
         type: "Failed to add to selected canvas",
         userMessage:
           "Failed to add to selected canvas. The team has been notified.",
         context: {
           pageUid,
-          results,
-          blockProps,
+          resultsCount: results.length,
+          sampleUids: results.slice(0, 5).map((r) => r.uid),
         },
       });

249-251: Add explicit return type annotation.

Per coding guidelines, functions should have explicit return types. After fixing the console.log return statements, this function should return Promise<boolean>.

🔎 Suggested fix
-  const addToSelectedCanvas = async (pageUid: string) => {
+  const addToSelectedCanvas = async (pageUid: string): Promise<boolean> => {

Based on coding guidelines: "Use explicit return types for functions".

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 903ae89 and 41ab966.

📒 Files selected for processing (2)
  • apps/roam/src/components/Export.tsx
  • apps/roam/src/components/canvas/useRoamStore.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

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

**/*.{ts,tsx}: Use Tailwind CSS for styling where possible
When refactoring inline styles, use tailwind classes
Prefer type over interface in TypeScript
Use explicit return types for functions
Avoid any types when possible
Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use PascalCase for components and types
Use camelCase for variables and functions
Use UPPERCASE for constants
Function names should describe their purpose clearly
Prefer early returns over nested conditionals for better readability

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/Export.tsx
apps/roam/**/*.{js,ts,tsx,jsx,json}

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

Prefer existing dependencies from package.json when working on the Roam Research extension

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/Export.tsx
apps/roam/**/*.{ts,tsx,jsx,js,css,scss}

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

Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/Export.tsx
apps/roam/**/*.{ts,tsx,js,jsx}

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

apps/roam/**/*.{ts,tsx,js,jsx}: Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality
Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/Export.tsx
apps/roam/**

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

Implement the Discourse Graph protocol in the Roam Research extension

Files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/Export.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality

Applied to files:

  • apps/roam/src/components/canvas/useRoamStore.ts
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Applied to files:

  • apps/roam/src/components/canvas/useRoamStore.ts
  • apps/roam/src/components/Export.tsx
🔇 Additional comments (3)
apps/roam/src/components/canvas/useRoamStore.ts (1)

32-39: LGTM!

Exporting isTLStoreSnapshot is appropriate for enabling cross-module interoperability with the new TLStoreSnapshot-based export flow in Export.tsx. The type guard implementation is correct and well-typed.

apps/roam/src/components/Export.tsx (2)

56-85: LGTM!

The new imports are correctly structured to support the TLStoreSnapshot-based export flow. The separation between tldraw and @tldraw/editor imports follows the established pattern.


635-638: LGTM!

The handleSendTo function correctly awaits the addToSelectedCanvas result and uses early return to abort on failure, preventing the success toast from displaying when the canvas update fails.

@mdroidian
Copy link
Contributor Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 1

Fix all issues with AI Agents 🤖
In @apps/roam/src/components/Export.tsx:
- Around line 305-418: The TLStore initialization block is duplicated; extract
it into a shared helper (e.g., createTLStoreForCanvas) that encapsulates calls
to getDiscourseRelations, createNodeShapeUtils, createAllRelationShapeUtils,
createAllReferencedNodeUtils, createAllRelationBindings,
createAllReferencedNodeBindings, createMigrations and createTLStore, and returns
the created tlStore and its snapshot (and optionally the serialized schema).
Replace the inline block in Export.tsx (which sets tldraw.schema and
tempTlStoreSnapshot) and the similar block in tldraw.tsx with a call to this
helper, assign tldraw.schema = returned.schema (or serialize tlStore.schema) and
tempTlStoreSnapshot = returned.tlStoreSnapshot, and update imports to use the
new utils/createTLStoreForCanvas export.
♻️ Duplicate comments (2)
apps/roam/src/components/Export.tsx (2)

249-251: Past review comment resolved.

The function signature now correctly returns Promise<boolean>, and the early return properly returns false instead of the previous return console.log(...) pattern that returned undefined.


421-468: Past review comment resolved.

The error handling now correctly uses internalError with explicit return false statements instead of return console.log(...). This fixes the inconsistent return type issue flagged in the previous review.

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41ab966 and f7e35fd.

📒 Files selected for processing (1)
  • apps/roam/src/components/Export.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

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

**/*.{ts,tsx}: Use Tailwind CSS for styling where possible
When refactoring inline styles, use tailwind classes
Prefer type over interface in TypeScript
Use explicit return types for functions
Avoid any types when possible
Prefer arrow functions over regular function declarations
Use named parameters (object destructuring) when a function has more than 2 parameters
Use PascalCase for components and types
Use camelCase for variables and functions
Use UPPERCASE for constants
Function names should describe their purpose clearly
Prefer early returns over nested conditionals for better readability

Files:

  • apps/roam/src/components/Export.tsx
apps/roam/**/*.{js,ts,tsx,jsx,json}

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

Prefer existing dependencies from package.json when working on the Roam Research extension

Files:

  • apps/roam/src/components/Export.tsx
apps/roam/**/*.{ts,tsx,jsx,js,css,scss}

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

Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Files:

  • apps/roam/src/components/Export.tsx
apps/roam/**/*.{ts,tsx,js,jsx}

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

apps/roam/**/*.{ts,tsx,js,jsx}: Use the roamAlphaApi docs from https://roamresearch.com/#/app/developer-documentation/page/tIaOPdXCj when implementing Roam functionality
Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Files:

  • apps/roam/src/components/Export.tsx
apps/roam/**

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

Implement the Discourse Graph protocol in the Roam Research extension

Files:

  • apps/roam/src/components/Export.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-25T00:52:41.934Z
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/roam.mdc:0-0
Timestamp: 2025-11-25T00:52:41.934Z
Learning: Applies to apps/roam/**/*.{ts,tsx,js,jsx} : Use Roam Depot/Extension API docs from https://roamresearch.com/#/app/developer-documentation/page/y31lhjIqU when implementing extension functionality

Applied to files:

  • apps/roam/src/components/Export.tsx
📚 Learning: 2025-10-18T18:58:16.100Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 504
File: apps/roam/src/utils/syncDgNodesToSupabase.ts:523-531
Timestamp: 2025-10-18T18:58:16.100Z
Learning: In `apps/roam/src/utils/syncDgNodesToSupabase.ts`, partial successes from `upsertNodesToSupabaseAsContent` and `addMissingEmbeddings` (indicated by numeric return values showing the count of successful operations) should NOT trigger backoff. Only complete failures (false) should trigger the exponential backoff mechanism. This design allows the sync process to continue making progress even when some items fail.

Applied to files:

  • apps/roam/src/components/Export.tsx
🧬 Code graph analysis (1)
apps/roam/src/components/Export.tsx (8)
apps/roam/src/components/canvas/Tldraw.tsx (2)
  • MAX_WIDTH (121-121)
  • discourseContext (112-117)
apps/roam/src/components/canvas/useRoamStore.ts (1)
  • isTLStoreSnapshot (32-39)
apps/roam/src/utils/getDiscourseRelations.ts (1)
  • DiscourseRelation (12-19)
apps/roam/src/components/canvas/DiscourseRelationShape/DiscourseRelationTool.tsx (1)
  • AddReferencedNodeType (15-15)
apps/roam/src/components/canvas/DiscourseNodeUtil.tsx (1)
  • createNodeShapeUtils (138-155)
apps/roam/src/components/canvas/DiscourseRelationShape/DiscourseRelationUtil.tsx (1)
  • createAllRelationShapeUtils (567-1048)
apps/roam/src/components/canvas/DiscourseRelationShape/DiscourseRelationBindings.tsx (2)
  • createAllRelationBindings (45-51)
  • createAllReferencedNodeBindings (36-44)
apps/roam/src/components/canvas/DiscourseRelationShape/discourseRelationMigrations.ts (1)
  • createMigrations (19-148)
🔇 Additional comments (4)
apps/roam/src/components/Export.tsx (4)

53-85: LGTM!

The new imports properly support the TLStore-based canvas integration. All imports are used in the refactored addToSelectedCanvas function.


253-303: Excellent legacy store handling.

The detection logic correctly identifies legacy stores and provides a user-friendly notification with a clickable link to the canvas page. Properly aborts the operation to prevent data corruption.


580-613: Excellent error handling.

The try/catch block properly handles Roam API failures and returns explicit boolean success/failure signals. The error context includes all relevant debugging information.


661-664: LGTM!

Properly checks the boolean return from addToSelectedCanvas and aborts on failure, preventing a false success message to the user.

@mdroidian mdroidian merged commit fd71e9f into main Jan 5, 2026
5 checks passed
@mdroidian mdroidian deleted the eng-952-inconsistent-send-nodes-to-canvas-behavior branch January 5, 2026 06:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants