Skip to content

Conversation

@maparent
Copy link
Collaborator

@maparent maparent commented Dec 19, 2025

https://linear.app/discourse-graphs/issue/ENG-1164/ability-to-add-a-canvas-page-to-the-clipboard-to-view-the-nodes-on

Allow the references in a Canvas page to be accessible through the Canvas clipboard.
Did this through simply expanding getAllReferencesOnPage to handle canvas pages.
Curious if this would have side effects on Hyde? I expect Hyde to never deal with Canvas pages.
Also: Could a Canvas page also have non-canvas node references?
Also: Can canvas references include non-node pages? I do not (yet) filter them out. Would that be required?

Summary by CodeRabbit

  • Refactor
    • Reorganized internal utilities for improved code maintainability.
    • Minor formatting adjustments to query structures with no functional impact.

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

@linear
Copy link

linear bot commented Dec 19, 2025

@supabase
Copy link

supabase bot commented Dec 19, 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 ↗︎.

@maparent
Copy link
Collaborator Author

@CodeRabbit review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 19, 2025

✅ 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.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 19, 2025

📝 Walkthrough

Walkthrough

Extract the getAllReferencesOnPage function from hyde.ts into a new dedicated module. Update imports in Clipboard.tsx and hyde.ts to reference the new location. Apply minor query formatting adjustments in Clipboard.tsx.

Changes

Cohort / File(s) Summary
Function extraction and module reorganization
apps/roam/src/utils/getAllReferencesOnPage.ts
New module created with getAllReferencesOnPage function that normalizes page titles, queries Roam API for canvas-related references or general page references, and returns array of {uid, text} objects.
apps/roam/src/utils/hyde.ts Removed local getAllReferencesOnPage function implementation; added import from new getAllReferencesOnPage module to maintain functionality.
apps/roam/src/components/canvas/Clipboard.tsx Updated import path for getAllReferencesOnPage from ~/utils/hyde to ~/utils/getAllReferencesOnPage; reformatted Roam API query where clauses with consolidated line breaks.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Verify the extracted function in the new module contains all original logic and handles both canvas and non-canvas page title cases correctly
  • Confirm import paths are correctly updated across all three files and resolve without errors
  • Ensure hyde.ts properly re-exports or uses the imported function from the new module

Pre-merge checks

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main feature being implemented: adding canvas pages to the clipboard to view their nodes, which aligns with the refactoring of getAllReferencesOnPage to handle canvas-specific logic.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

🧹 Nitpick comments (1)
apps/roam/src/utils/getAllReferencesOnPage.ts (1)

12-24: Add validation for type assertions.

The code uses type assertions (as Array<[string, string]>) without validating the actual structure of the data returned from Roam queries. If the query returns unexpected data, this could lead to runtime errors.

Consider adding runtime validation before the type assertions:

🔎 Suggested validation approach
const validateQueryResult = (result: unknown): result is Array<[string, string]> => {
  return (
    Array.isArray(result) &&
    result.every(
      (item) =>
        Array.isArray(item) &&
        item.length === 2 &&
        typeof item[0] === "string" &&
        typeof item[1] === "string"
    )
  );
};

// Then use it:
const oldCanvasContent = window.roamAlphaAPI.data.fast.q(/* query */);
if (!validateQueryResult(oldCanvasContent)) {
  console.error("Unexpected query result format for oldCanvasContent");
  return [];
}

Also applies to: 25-38, 41-51

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7b4cb58 and bead0e3.

📒 Files selected for processing (3)
  • apps/roam/src/components/canvas/Clipboard.tsx (2 hunks)
  • apps/roam/src/utils/getAllReferencesOnPage.ts (1 hunks)
  • apps/roam/src/utils/hyde.ts (1 hunks)
🧰 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/utils/getAllReferencesOnPage.ts
  • apps/roam/src/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.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/utils/getAllReferencesOnPage.ts
  • apps/roam/src/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.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/utils/getAllReferencesOnPage.ts
  • apps/roam/src/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.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/utils/getAllReferencesOnPage.ts
  • apps/roam/src/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.tsx
apps/roam/**

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

Implement the Discourse Graph protocol in the Roam Research extension

Files:

  • apps/roam/src/utils/getAllReferencesOnPage.ts
  • apps/roam/src/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.tsx
🧠 Learnings (7)
📚 Learning: 2025-11-05T21:57:14.909Z
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 534
File: apps/roam/src/utils/createReifiedBlock.ts:40-48
Timestamp: 2025-11-05T21:57:14.909Z
Learning: In the discourse-graph repository, the function `getPageUidByPageTitle` from `roamjs-components/queries/getPageUidByPageTitle` is a synchronous function that returns a string directly (the page UID or an empty string if not found), not a Promise. It should be called without `await`.

Applied to files:

  • apps/roam/src/utils/getAllReferencesOnPage.ts
  • apps/roam/src/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 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/getAllReferencesOnPage.ts
  • apps/roam/src/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 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/utils/getAllReferencesOnPage.ts
  • apps/roam/src/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 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/utils/hyde.ts
  • apps/roam/src/components/canvas/Clipboard.tsx
📚 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/** : Implement the Discourse Graph protocol in the Roam Research extension

Applied to files:

  • apps/roam/src/utils/hyde.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,jsx,js,css,scss} : Use BlueprintJS 3 components and Tailwind CSS for platform-native UI in the Roam Research extension

Applied to files:

  • apps/roam/src/components/canvas/Clipboard.tsx
📚 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/**/*.{js,ts,tsx,jsx,json} : Prefer existing dependencies from package.json when working on the Roam Research extension

Applied to files:

  • apps/roam/src/components/canvas/Clipboard.tsx
🔇 Additional comments (4)
apps/roam/src/components/canvas/Clipboard.tsx (1)

42-42: LGTM! Import updated correctly.

The import path has been correctly updated to reference the newly extracted getAllReferencesOnPage utility module.

apps/roam/src/utils/hyde.ts (1)

9-9: LGTM! Import added correctly.

The import correctly references the newly extracted getAllReferencesOnPage module, maintaining the same functionality while improving code modularity.

apps/roam/src/utils/getAllReferencesOnPage.ts (2)

6-8: Add explicit return type annotation.

As per coding guidelines, functions should have explicit return types for better type safety and documentation.

🔎 Proposed fix
-const getAllReferencesOnPage = async (
-  pageTitle: string,
-): Promise<{ uid: string; text: string }[]> => {
+const getAllReferencesOnPage = async (
+  pageTitle: string
+): Promise<Array<{ uid: string; text: string }>> => {
⛔ Skipped due to learnings
Learnt from: maparent
Repo: DiscourseGraphs/discourse-graph PR: 534
File: apps/roam/src/utils/createReifiedBlock.ts:40-48
Timestamp: 2025-11-05T21:57:14.909Z
Learning: In the discourse-graph repository, the function `getPageUidByPageTitle` from `roamjs-components/queries/getPageUidByPageTitle` is a synchronous function that returns a string directly (the page UID or an empty string if not found), not a Promise. It should be called without `await`.
Learnt from: CR
Repo: DiscourseGraphs/discourse-graph PR: 0
File: .cursor/rules/main.mdc:0-0
Timestamp: 2025-11-25T00:52:27.779Z
Learning: Applies to **/*.{ts,tsx} : Use explicit return types for functions

11-39: Verify whether Canvas pages can contain regular block references alongside canvas shapes.

The current implementation assumes Canvas pages contain only tldraw shapes and never checks for regular [[page-reference]] links on Canvas pages (lines 11-39), whereas non-Canvas pages do query for block references (lines 40-52). If Canvas pages can have both content types, the logic should query both tldraw shapes and :block/refs for Canvas pages and merge the results.

@@ -0,0 +1,56 @@
import getExtensionAPI from "roamjs-components/util/extensionApiContext";
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove unused import.

The getExtensionAPI import is not used in this module (only in the commented-out code at line 4).

🔎 Proposed fix
-import getExtensionAPI from "roamjs-components/util/extensionApiContext";
 import normalizePageTitle from "roamjs-components/queries/normalizePageTitle";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import getExtensionAPI from "roamjs-components/util/extensionApiContext";
import normalizePageTitle from "roamjs-components/queries/normalizePageTitle";
🤖 Prompt for AI Agents
In apps/roam/src/utils/getAllReferencesOnPage.ts around line 1, the import
`getExtensionAPI` is unused (only referenced in commented-out code); remove the
unused import statement to clean up the module and update any related linter
warnings, or if the commented code will be re-enabled later, move the import
next to that code and keep it commented as well.

import getExtensionAPI from "roamjs-components/util/extensionApiContext";
import normalizePageTitle from "roamjs-components/queries/normalizePageTitle";

// getExtensionAPI();
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Remove commented-out code.

The commented line appears to be a debugging artifact and should be removed to keep the codebase clean.

🔎 Proposed fix
 import normalizePageTitle from "roamjs-components/queries/normalizePageTitle";
 
-// getExtensionAPI();
-
 const getAllReferencesOnPage = async (
🤖 Prompt for AI Agents
In apps/roam/src/utils/getAllReferencesOnPage.ts around line 4, remove the
commented-out debugging artifact "// getExtensionAPI();" to clean up the
codebase; simply delete that line so only active code remains and run
linting/formatting to ensure no trailing whitespace.

@maparent
Copy link
Collaborator Author

@maparent
Copy link
Collaborator Author

@CodeRabbit and @mdroidian
I think that making type assertions at the boundary of two systems is warranted in general.
Here, we know the output shape from the datalog query structure.

@maparent maparent requested a review from mdroidian December 19, 2025 16:59
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 19, 2025

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the content of the new getAllReferencesOnPage.ts file to see type assertions
cat apps/roam/src/utils/getAllReferencesOnPage.ts

Length of output: 1767


🏁 Script executed:

#!/bin/bash
# Get the updated Clipboard.tsx to see how it uses the function
cat apps/roam/src/components/canvas/Clipboard.tsx

Length of output: 35492


🏁 Script executed:

#!/bin/bash
# Get hyde.ts to see what changed there
cat apps/roam/src/utils/hyde.ts

Length of output: 14814


@maparent, that's a sound approach. When interfacing with external systems like Roam's datalog queries, type assertions at the boundary are appropriate since the :find clause explicitly defines the output structure—in these cases, tuples of [string, string] for ?uid ?title or ?uid ?text pairs. The TypeScript compiler can't infer this from the query string, so the assertion bridges that gap safely.


✏️ Learnings added
Learnt from: maparent
URL: https://github.com/DiscourseGraphs/discourse-graph/pull/627

Timestamp: 2025-12-19T16:59:40.629Z
Learning: In this codebase, type assertions at system boundaries (e.g., Roam datalog queries) are acceptable when the output shape is known from the query structure, such as when using `as Array<[string, string]>` after datalog queries with `:find ?uid ?title` clauses.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

Copy link
Contributor

@mdroidian mdroidian left a comment

Choose a reason for hiding this comment

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

We need to grab the defined canvas page format, but looks good other than that.

Curious if this would have side effects on Hyde? I expect Hyde to never deal with Canvas pages.

Should be fine.

Also: Could a Canvas page also have non-canvas node references?

Currently, all references are dg node shapes.

Also: Can canvas references include non-node pages? I do not (yet) filter them out. Would that be required?

Yes. But this is already filtered out elsewhere.

): Promise<{ uid: string; text: string }[]> => {
pageTitle = normalizePageTitle(pageTitle);
let referencedPages: Array<[string, string]> = [];
if (pageTitle.startsWith("Canvas/")) {
Copy link
Contributor

@mdroidian mdroidian Dec 22, 2025

Choose a reason for hiding this comment

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

Canvas page format is defined in settings, so this could change. Let's make sure we grab the up to date format.


const getAllReferencesOnPage = async (
pageTitle: string,
): Promise<{ uid: string; text: string }[]> => {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: uid;text; is Result[], which is commonly used in the repo

pageTitle = normalizePageTitle(pageTitle);
let referencedPages: Array<[string, string]> = [];
if (pageTitle.startsWith("Canvas/")) {
const oldCanvasContent = window.roamAlphaAPI.data.fast.q(
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: we should see if we can reuse some code with CanvasReferences

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.

3 participants