Skip to content

Conversation

sid597
Copy link
Collaborator

@sid597 sid597 commented Aug 17, 2025

Summary by CodeRabbit

  • New Features

    • End-to-end sync of Roam discourse nodes to the database, including embeddings and concepts.
    • Per-type node retrieval with richer node data (author, type, optional title).
    • Progress reporting during embedding fetches.
  • Performance

    • Larger embedding batch size for faster processing.
    • Targeted updates by detecting node types with recent changes.
  • Reliability

    • Improved orphaned data cleanup for nodes and schemas.
    • More robust error handling and task coordination during sync.
  • Developer Experience

    • Clearer, configurable embedding model usage.

Copy link

linear bot commented Aug 17, 2025

Copy link

supabase bot commented Aug 17, 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 ↗︎.

@sid597
Copy link
Collaborator Author

sid597 commented Aug 17, 2025

@coderabbitai full review

Copy link
Contributor

coderabbitai bot commented Aug 17, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

coderabbitai bot commented Aug 17, 2025

📝 Walkthrough

Walkthrough

Refactors orphaned-node cleanup to use explicit Supabase client/context; updates embeddings utility types/model/batch size; overhauls discourse-node retrieval to per-type with extension settings; adds a new sync orchestrator that coordinates task lifecycle, embeddings upsert, concept conversion, and cleanup; introduces a helper module to upsert nodes as content with embeddings.

Changes

Cohort / File(s) Summary
Cleanup Orphaned Nodes refactor
apps/roam/src/utils/cleanupOrphanedNodes.ts
Switches to explicit DGSupabaseClient and context; splits retrieval into schema and block phases; adds schema cascade deletion; revises exported cleanupOrphanedNodes(supabaseClient, context).
Embeddings fetch update
apps/roam/src/utils/fetchEmbeddingsForNodes.ts
Replaces local type with RoamDiscourseNodeData; batch size 200; introduces EMBEDDING_MODEL; prefixes title to text; returns nodes with model/vector; updates function signature.
Discourse nodes retrieval overhaul
apps/roam/src/utils/getAllDiscourseNodesSince.ts
Adds per-type retrieval, settings-based block extraction, filtering; new exports (getDiscourseNodeTypeWithSettingsBlockNodes, nodeTypeSince, DiscourseNodesSinceResult); expands RoamDiscourseNodeData; updates getAllDiscourseNodesSince signature to include nodeTypes and extensionAPI.
Sync orchestrator (new)
apps/roam/src/utils/syncDgNodesToSupabase.ts
New end-to-end sync: proposes/ends tasks via RPC, fetches embeddings, upserts content, converts to concepts, orders dependencies, upserts concepts, runs orphan cleanup; exposes proposeSyncTask, endSyncTask, conversion/upsert helpers, and createOrUpdateDiscourseEmbedding.
Upsert with embeddings (new)
apps/roam/src/utils/upsertNodesAsContentWithEmbeddings.ts
Adds embedding fetch (batch 200, model openai_text_embedding_3_small_1536) and batch upsert to Supabase via upsert_content; exported fetchEmbeddingsForNodes and upsertNodesToSupabaseAsContentWithEmbeddings.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Ext as Roam Extension
  participant Sync as createOrUpdateDiscourseEmbedding
  participant SB as Supabase RPC/API
  participant Emb as Embedding Service

  Ext->>Sync: Trigger sync
  Sync->>SB: propose_sync_task()
  SB-->>Sync: SyncTaskInfo (worker/timeout)
  Sync->>Ext: get nodeTypes & settings
  Sync->>Ext: getAllDiscourseNodesSince(since, nodeTypes, extensionAPI)
  Sync->>Emb: fetchEmbeddingsForNodes(batches)
  Emb-->>Sync: vectors
  Sync->>SB: upsert_content(batched)
  Sync->>SB: upsert_concepts(ordered)
  Sync->>SB: cleanupOrphanedNodes(client, context)
  Sync->>SB: end_sync_task(status="complete")
Loading
sequenceDiagram
  autonumber
  participant Caller
  participant Clean as cleanupOrphanedNodes
  participant SB as Supabase

  Caller->>Clean: cleanupOrphanedNodes(client, context)
  Clean->>SB: fetch schema node UIDs
  SB-->>Clean: schema UIDs
  Clean->>SB: fetch block content nodes
  SB-->>Clean: block node UIDs
  Clean->>SB: delete orphaned schemas (+content/concepts/docs)
  SB-->>Clean: deleted counts
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Possibly related PRs

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (8)
apps/roam/src/utils/cleanupOrphanedNodes.ts (3)

16-19: Redundant null check for context

The context parameter is typed as non-nullable SupabaseContext, but Line 16 still checks if it's falsy. This check is unnecessary given the type signature.

Remove the redundant check:

-    if (!context) {
-      console.error("Failed to get Supabase context");
-      return [];
-    }
     const { spaceId } = context;

102-105: Duplicate null check pattern

Similar to the previous comment, this null check is redundant given the non-nullable type signature.

Remove the redundant check:

-    if (!context) {
-      console.error("Failed to get Supabase context");
-      return [];
-    }

40-66: Performance: Consider chunking large IN clause queries

When schemaIds contains many elements, the IN clause at Line 52 could potentially hit database query limits or performance issues.

Consider chunking large arrays:

     if (schemaIds.length > 0) {
+      const CHUNK_SIZE = 500; // Adjust based on DB limits
+      const chunks = [];
+      for (let i = 0; i < schemaIds.length; i += CHUNK_SIZE) {
+        chunks.push(schemaIds.slice(i, i + CHUNK_SIZE));
+      }
+      
+      const results = [];
+      for (const chunk of chunks) {
       const conceptResponse = await supabaseClient
         .from("Concept")
         .select(
           `
         Content!inner (
             source_local_id
         )
       `,
         )
         .eq("space_id", spaceId)
         .eq("is_schema", false)
-        .in("schema_id", schemaIds)
+        .in("schema_id", chunk)
         .not("Content.source_local_id", "is", null);
 
       if (conceptResponse.error) {
         console.error(
           "Failed to get concepts from Supabase:",
           conceptResponse.error,
         );
         return [];
       }
+        results.push(...(conceptResponse.data || []));
+      }
       nodeResult =
-        conceptResponse.data
+        results
           ?.map((c) => c.Content?.source_local_id)
           .filter((id): id is string => !!id) || [];
     }
apps/roam/src/utils/getAllDiscourseNodesSince.ts (1)

149-171: Check for duplicates when filtering node types

The nodeTypeSince function doesn't validate whether nodeTypes contains duplicates, which could lead to redundant queries if the same node type appears multiple times.

Add deduplication:

 export const nodeTypeSince = async (
   since: ISODateString,
   nodeTypes: DiscourseNode[],
 ) => {
   const sinceMs = new Date(since).getTime();
+  // Deduplicate node types by their type property
+  const uniqueNodeTypes = Array.from(
+    new Map(nodeTypes.map(node => [node.type, node])).values()
+  );
   const filterMap = await Promise.all(
-    nodeTypes.map((node) => {
+    uniqueNodeTypes.map((node) => {
       const query = `
       [:find ?node-title
        :in $ ?since ?type
        :where
         [?node :block/uid ?type]
         [?node :node/title ?node-title]
         [?node :edit/time ?nodeEditTime]
         [(> ?nodeEditTime ?since)]]
     `;
       const result = window.roamAlphaAPI.data.q(query, sinceMs, node.type);
       return result.length > 0;
     }),
   );
 
-  const nodesSince = nodeTypes.filter((_, index) => filterMap[index]);
+  const nodesSince = uniqueNodeTypes.filter((_, index) => filterMap[index]);
   return nodesSince;
 };
apps/roam/src/utils/syncDgNodesToSupabase.ts (1)

241-241: Destructuring unused variable

The destructuring includes a variable that isn't used in the subsequent code.

Remove the unused variable:

-  const { ordered } = orderConceptsByDependency(conceptsToUpsert);
-  const {  error } = await supabaseClient.rpc("upsert_concepts", {
+  const { ordered } = orderConceptsByDependency(conceptsToUpsert);
+  const { error } = await supabaseClient.rpc("upsert_concepts", {
apps/roam/src/utils/upsertNodesAsContentWithEmbeddings.ts (3)

20-20: Remove debug console.log statement

Debug logging statement should be removed from production code.

   const allEmbeddings: number[][] = [];
-  console.log("nodes", nodes);
   const allNodesTexts = nodes.map((node) =>

126-130: Redundant context check

The context parameter is already destructured on Line 130, but there's a null check on Line 126. Since TypeScript enforces non-nullable types, this check is redundant.

Remove the redundant check:

 ): Promise<void> => {
-  if (!context) {
-    console.error("No Supabase context found.");
-    return;
-  }
   const { spaceId, userId } = context;

108-108: Type assertion with as any bypasses type safety

Using as any for the data parameter bypasses TypeScript's type checking and could hide type mismatches.

Consider proper typing or documenting why the assertion is necessary:

     const { error } = await supabaseClient.rpc("upsert_content", {
-      data: contents as any,
+      // TODO: Fix type mismatch between LocalContentDataInput and RPC expected type
+      data: contents as any, // Type assertion needed due to RPC type definition
       v_space_id: spaceId,
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between ca2f93b and 37aa7e0.

📒 Files selected for processing (5)
  • apps/roam/src/utils/cleanupOrphanedNodes.ts (3 hunks)
  • apps/roam/src/utils/fetchEmbeddingsForNodes.ts (3 hunks)
  • apps/roam/src/utils/getAllDiscourseNodesSince.ts (1 hunks)
  • apps/roam/src/utils/syncDgNodesToSupabase.ts (1 hunks)
  • apps/roam/src/utils/upsertNodesAsContentWithEmbeddings.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: maparent
PR: DiscourseGraphs/discourse-graph#182
File: apps/website/app/utils/supabase/dbUtils.ts:22-28
Timestamp: 2025-05-30T14:49:24.016Z
Learning: In apps/website/app/utils/supabase/dbUtils.ts, expanding the KNOWN_EMBEDDINGS and DEFAULT_DIMENSIONS mappings to support additional embedding models requires corresponding database model changes (creating new embedding tables), which should be scoped as separate work from API route implementations.
📚 Learning: 2025-05-30T14:49:24.016Z
Learnt from: maparent
PR: DiscourseGraphs/discourse-graph#182
File: apps/website/app/utils/supabase/dbUtils.ts:22-28
Timestamp: 2025-05-30T14:49:24.016Z
Learning: In apps/website/app/utils/supabase/dbUtils.ts, expanding the KNOWN_EMBEDDINGS and DEFAULT_DIMENSIONS mappings to support additional embedding models requires corresponding database model changes (creating new embedding tables), which should be scoped as separate work from API route implementations.

Applied to files:

  • apps/roam/src/utils/upsertNodesAsContentWithEmbeddings.ts
  • apps/roam/src/utils/syncDgNodesToSupabase.ts
  • apps/roam/src/utils/fetchEmbeddingsForNodes.ts
📚 Learning: 2025-06-22T10:40:52.752Z
Learnt from: sid597
PR: DiscourseGraphs/discourse-graph#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/fetchEmbeddingsForNodes.ts
  • apps/roam/src/utils/getAllDiscourseNodesSince.ts
📚 Learning: 2025-06-22T10:40:21.679Z
Learnt from: sid597
PR: DiscourseGraphs/discourse-graph#232
File: apps/roam/src/utils/getAllDiscourseNodesSince.ts:15-16
Timestamp: 2025-06-22T10:40:21.679Z
Learning: In the getAllDiscourseNodesSince function in apps/roam/src/utils/getAllDiscourseNodesSince.ts, date validation is performed before the function is called, so additional date validation within the function is not needed.

Applied to files:

  • apps/roam/src/utils/getAllDiscourseNodesSince.ts
🧬 Code Graph Analysis (5)
apps/roam/src/utils/cleanupOrphanedNodes.ts (3)
packages/ui/src/lib/supabase/client.ts (1)
  • DGSupabaseClient (9-13)
packages/database/types.gen.ts (1)
  • Database (9-819)
apps/roam/src/utils/supabaseContext.ts (3)
  • SupabaseContext (21-26)
  • getSupabaseContext (50-88)
  • getLoggedInClient (92-110)
apps/roam/src/utils/upsertNodesAsContentWithEmbeddings.ts (6)
apps/roam/src/utils/fetchEmbeddingsForNodes.ts (1)
  • fetchEmbeddingsForNodes (13-70)
apps/roam/src/utils/getAllDiscourseNodesSince.ts (1)
  • RoamDiscourseNodeData (8-18)
packages/ui/src/lib/supabase/client.ts (1)
  • DGSupabaseClient (9-13)
apps/roam/src/utils/supabaseContext.ts (1)
  • SupabaseContext (21-26)
packages/database/inputTypes.ts (1)
  • LocalContentDataInput (6-12)
apps/roam/src/utils/syncDgNodesToSupabase.ts (1)
  • upsertNodesToSupabaseAsContentWithEmbeddings (252-331)
apps/roam/src/utils/syncDgNodesToSupabase.ts (6)
apps/roam/src/utils/supabaseContext.ts (3)
  • getLoggedInClient (92-110)
  • getSupabaseContext (50-88)
  • SupabaseContext (21-26)
packages/ui/src/lib/supabase/client.ts (1)
  • DGSupabaseClient (9-13)
apps/roam/src/utils/getAllDiscourseNodesSince.ts (3)
  • RoamDiscourseNodeData (8-18)
  • nodeTypeSince (148-171)
  • getAllDiscourseNodesSince (76-146)
packages/database/inputTypes.ts (1)
  • LocalContentDataInput (6-12)
apps/roam/src/utils/conceptConversion.ts (5)
  • discourseNodeSchemaToLocalConcept (54-66)
  • discourseRelationSchemaToLocalConcept (92-115)
  • discourseNodeBlockToLocalConcept (68-88)
  • discourseRelationDataToLocalConcept (117-168)
  • orderConceptsByDependency (218-231)
apps/roam/src/utils/cleanupOrphanedNodes.ts (1)
  • cleanupOrphanedNodes (373-403)
apps/roam/src/utils/fetchEmbeddingsForNodes.ts (1)
apps/roam/src/utils/getAllDiscourseNodesSince.ts (1)
  • RoamDiscourseNodeData (8-18)
apps/roam/src/utils/getAllDiscourseNodesSince.ts (1)
apps/obsidian/src/utils/getDiscourseNodeFormatExpression.ts (1)
  • getDiscourseNodeFormatExpression (1-9)

@sid597 sid597 requested review from maparent and mdroidian August 17, 2025 17:16
export const getDiscourseNodeTypeWithSettingsBlockNodes = (
node: DiscourseNode,
sinceMs: number,
extensionAPI: OnloadArgs["extensionAPI"],
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will update this to use configTree when this is merged to main and rebase the UI branch off it

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.

Let's try to clean up as much of the warning/errors as possible in a first round pass.

If you aren't seeing these, let me know
image

image

@sid597 sid597 requested a review from mdroidian August 19, 2025 16:29
Copy link
Collaborator

@maparent maparent left a comment

Choose a reason for hiding this comment

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

I want to see what it looks like with a better type boundary, and then I'll look again at some of the update logic (but that looks good overall.)

}
};

export const convertDgToSupabaseConcepts = async (
Copy link
Collaborator

Choose a reason for hiding this comment

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

This converts and uploads. I think the name should reflect this. (Or better still, have this function return the converted concepts, and another function that calls this and upload. It'll be easier to test the former.)

@sid597 sid597 requested a review from maparent August 21, 2025 18:22
@maparent
Copy link
Collaborator

Ok, thanks a lot for the deduplication and type boundaries, much clearer to read.
I wanted to test it, but I notice that createOrUpdateDiscourseEmbedding is not called anywhere yet. Do you see that happening in another PR? I guess I should add a button in the admin panel on my side :-)
A last concern: You decided to materialize all four kinds of concepts (node schema, node, relation schemas, relations.) I did not look into how you get the relation instance nodes, is getDiscourseRelationTriples exhaustive?
More important: I wonder if the underlying content is always present for relation concepts? I get the impression that the content upload is limited to nodes, but again did not look deep into the roam queries. If not, I say let's wait for the relation schemas.
(This is what I wanted to test!)
Otherwise, lgtm.

@sid597
Copy link
Collaborator Author

sid597 commented Aug 22, 2025

@maparent Yeah I was not sure if we want to include the relations now, I think we should leave it for now, I will remove it from the function, thanks.

The function will be called from the UI component I will update the callers on that pr #327

We want to merge this pr first then #344 then #327 then #340

Copy link
Collaborator

@maparent maparent left a comment

Choose a reason for hiding this comment

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

Good. I'll trust you checked the runtime. LGTM.

@sid597
Copy link
Collaborator Author

sid597 commented Aug 22, 2025

@maparent Now you can use the branch locally the upsert will automatically start on plugin load, also review the changes in this commit e3f7352

@maparent maparent self-requested a review August 22, 2025 19:54
@sid597
Copy link
Collaborator Author

sid597 commented Aug 23, 2025

@maparent it worked for me when I tested it a few times then I pushed the commit and asked you for review, now when I tried to test it again on a different graph after reading your exp. Its failing on my end also I am getting the error:

Access to fetch at 'http://127.0.0.1:54321/functions/v1/create-space' from origin 'https://roamresearch.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
supabaseContext.ts:82 Error: Failed to create space
    at getSupabaseContext (supabaseContext.ts:65:36)
    at async getLoggedInClient (supabaseContext.ts:93:21)
    at async proposeSyncTask (syncDgNodesToSupabase.ts:66:28)
    at async createOrUpdateDiscourseEmbedding (syncDgNodesToSupabase.ts:316:53)

There is another type of bug that I am getting like

upsert_content failed for batch 1: {code: '23502', details: null, hint: null, message: 'null value in column "author_id" of relation "Document" violates not-null constraint'}

This bug I don't know refers to what, checking data that is passed on to upsert_content every data entry has the same author_id idk what this is refering to.

All the bugs are quite confusing because I tried this in a personal graph which has 4 nodes to test it on small batch and it works (it also worked yesterday)

image image

@maparent
Copy link
Collaborator

Ok. First apologies: The commit was a red herring, I was tired yesterday.
The first error you get may be due to missing cors policies, I think this is a change in supabase, corrected in ENG-758, you may have to merge that into your branch.
The second error is what started me on looking deeper into this. Basically, you need to make sure the authors of the documents exist. I am going to add a small fix so that the authors are created if absent, that's currently missing; but it's not the real solution. Ideally we should upsert all authors/creators before we upsert the content. That's going to be so much more efficient than putting them inline every time.
It's likely you missed that error earlier on your test graph because there were not that many authors (besides yourself as the logged in user.)
Working on a bulk uploading function, that will help.

@maparent
Copy link
Collaborator

Bulk functions pushed in #357

Add functions to upsert platform accounts (individually or in bulk)
Keep the old create_account_in_space function as a shim for now.
Use the new upsert_account in upsert_documents and upsert_content,
allowing for more complete inline information.
@sid597
Copy link
Collaborator Author

sid597 commented Aug 23, 2025

Yeah the personal graph only has me as the user but the other graph discourse-dev-graph has many users and it worked on it yesterday, and I was remembering that we create the users if they don't exist, might me mis-remembering or smth.

maparent and others added 7 commits August 23, 2025 11:06
Add functions to upsert platform accounts (individually or in bulk)
Keep the old create_account_in_space function as a shim for now.
Use the new upsert_account in upsert_documents and upsert_content,
allowing for more complete inline information.
Add functions to upsert platform accounts (individually or in bulk)
Keep the old create_account_in_space function as a shim for now.
Use the new upsert_account in upsert_documents and upsert_content,
allowing for more complete inline information.
Copy link
Collaborator

@maparent maparent left a comment

Choose a reason for hiding this comment

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

Ok, this basically lgtm. One small nit before you push: There are a lot of imports that could be import type {...} ..., or at least import {x, type y} ..., fwiw.

? `${node.node_title} ${node.text}`
: node.text;
return {
author_id: userId,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually... this is wrong, as it makes the current user the author of all nodes. In theory, you should not have to set this, since you set author_local_id; but in practice, the author_local_id may not have been materialized in the database, which may lead to the insert failing. So make sure to collect all author_ids and creator_ids, and to create platformAccounts (prob. with createAccountInSpace; I will create a bulk version of that.)

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 did not see this comment before I need to learn the github ui better

@sid597 sid597 merged commit 7cb2e08 into main Aug 24, 2025
5 checks passed
@github-project-automation github-project-automation bot moved this to Done in General Aug 24, 2025
]`;

//@ts-ignore - backend to be added to roamjs-components
const allNodes = (await window.roamAlphaAPI.data.async.q(
Copy link
Contributor

Choose a reason for hiding this comment

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

@sid597 This should probably be .backend. We can discuss at our next meeting.

[(> ?nodeEditTime ?since)]]
]`;

const blockNode = window.roamAlphaAPI.data.q(
Copy link
Contributor

Choose a reason for hiding this comment

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

@sid597 This should probably be .backend. We can discuss at our next meeting.

if (!entity.source_local_id) {
return [];
}
const node = findDiscourseNode(entity.source_local_id, discourseNodes);
Copy link
Contributor

Choose a reason for hiding this comment

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

@sid597 This will likely need to be a custom function. findDiscourseNode will likely be a performance issue on large graphs. We can discuss at our next meeting.

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

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants