Skip to content

ENG-2038 Add admin-flagged node card context menu to Obsidian tldraw - #1255

Open
sid597 wants to merge 5 commits into
mainfrom
eng-2038-add-admin-flagged-node-card-context-menu-to-obsidian-tldraw
Open

ENG-2038 Add admin-flagged node card context menu to Obsidian tldraw#1255
sid597 wants to merge 5 commits into
mainfrom
eng-2038-add-admin-flagged-node-card-context-menu-to-obsidian-tldraw

Conversation

@sid597

@sid597 sid597 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • add a default-off admin flag for the Obsidian node-card context menu
  • replace tldraw's style panel only when a single discourse-node is selected
  • show Context by default and reuse tldraw's native styling controls in the Styling tab
  • embed the existing relation-panel actions in Context
  • show incoming and outgoing relation groups in the new menu, including configured empty groups and deduplicated linked files
  • preserve the existing relation overlay and regular tldraw shape behavior
  • add one CSS rule to widen this menu because tldraw hard-caps its style panel at 148 px

Behavior boundaries

  • Flag off, non-discourse selections, and multi-select continue to render tldraw's stock DefaultStylePanel.
  • includeAllDirections is explicit at the new menu call site; embedded controls layout only.
  • The legacy relations panel keeps its prior behavior: matchingRelations.slice(0, 1) uses the same predicate and first match as the previous .find(...), and its counterpart lookup is unchanged.
  • The new menu opts into all configured directions without changing the legacy overlay.
  • The localized ComponentType casts are required because tldraw is typed against React 19 while the Obsidian app runs React 18; plain JSX adds TS2786 diagnostics. The repository-wide React type mismatch is intentionally out of scope.

Scope

This PR changes seven Obsidian production files only. It adds one load-bearing CSS rule and no test command, test framework, dependency, lockfile change, or standalone model layer.

Linear: https://linear.app/discourse-graphs/issue/ENG-2038/add-admin-flagged-node-card-context-menu-to-obsidian-tldraw

Validation

  • pnpm --filter @discourse-graphs/obsidian build — built with 0 errors
  • package-local ESLint over all changed TypeScript files — passed with 0 warnings/errors
  • Prettier and git diff --check — passed
  • built CSS contains the width override and the defined tldraw --color-text-3 token

Known validation gaps

  • the interaction has not yet been driven in a live Obsidian vault; no running Obsidian process, configured plugin mirror, or project-local vault was available in this environment
  • the vault drive must include discourse node → plain rectangle → discourse node in both themes to inspect the selection-conditional 148 px ↔ 320 px width change for jitter or poor content reflow; add a transition only if that runtime behavior reads badly
  • ENG-2038's automated-test Done-When is not met: apps/obsidian has no test harness, and a deferral ticket plus the ticket owner's acceptance are still required
  • package-wide check-types remains red with the same 20 pre-existing tldraw/React JSX type-identity diagnostics; no diagnostic is introduced in NodeCardContextMenu or RelationPanel
  • local validation used Node 20.20.2 while the repository declares Node >=22; pnpm emitted an engine warning

@linear-code

linear-code Bot commented Jul 27, 2026

Copy link
Copy Markdown

ENG-2038

@supabase

supabase Bot commented Jul 27, 2026

Copy link
Copy Markdown

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

@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
discourse-graph Skipped Skipped Jul 27, 2026 5:21pm

Request Review

@sid597
sid597 marked this pull request as ready for review July 31, 2026 05:57
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@sid597

sid597 commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 2 additional findings in Devin Review.

Open in Devin Review

Comment on lines +84 to +94
{activeTab === "context" ? (
<RelationsPanel
plugin={plugin}
canvasFile={canvasFile}
nodeShape={selectedNode}
embedded
includeAllDirections
/>
) : (
createElement(DefaultStylePanelContentComponent, { styles })
)}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔴 Selecting a node card silently edits the canvas note and can append duplicate link blocks

The relations list is now shown automatically whenever a single node card is selected (RelationsPanel at apps/obsidian/src/components/canvas/NodeCardContextMenu.tsx:85-91), and merely showing it writes new link blocks into the canvas note, so users get unexpected file edits just by clicking a card.
Impact: Clicking a node card can modify the saved canvas note without any user action, and repeated re-renders while dragging can append the same link text over and over.

How rendering the relations list triggers vault writes

Each listed related file is rendered as a RelationFileItem, whose mount effect calls checkExistingRelation (apps/obsidian/src/components/canvas/overlays/RelationPanel.tsx:76-90). checkExistingRelation calls ensureBlockRefForFile (apps/obsidian/src/components/canvas/overlays/RelationPanel.tsx:269-273), which, when no existing block ref points at the target file, appends [[link]]\n^uuid to the canvas markdown via app.vault.process (apps/obsidian/src/components/canvas/stores/assetStore.ts:143-155).

Previously this only ran after the user explicitly opened the floating Relations panel via the overlay button (apps/obsidian/src/components/canvas/overlays/RelationOverlay.tsx:80-101). With the new style-panel menu the panel mounts on every single-node selection.

Additionally, checkExistingRelation is re-created on every RelationsPanel render and is in the effect's dependency array, and NodeCardContextMenu re-renders whenever the selected shape record changes (e.g. while dragging, via useValue at apps/obsidian/src/components/canvas/NodeCardContextMenu.tsx:42-46). Because Obsidian's metadataCache updates asynchronously, consecutive invocations can miss the just-written block and append another duplicate block for the same file.

Prompt for agents
Rendering RelationsPanel now happens automatically on node selection (NodeCardContextMenu Context tab), but the panel's per-item relation check has a side effect: checkExistingRelation in apps/obsidian/src/components/canvas/overlays/RelationPanel.tsx calls ensureBlockRefForFile, which appends a new '[[link]]\n^uuid' block to the canvas markdown file (apps/obsidian/src/components/canvas/stores/assetStore.ts) when none exists. This means merely selecting a card mutates the note. It is also re-run on every re-render because checkExistingRelation is re-created each render and is an effect dependency, and metadataCache lag can cause duplicate appends.

Possible approaches: introduce a read-only lookup (e.g. resolve an existing block ref without creating one) for the existence check, and only call ensureBlockRefForFile when the user actually creates a relation; and/or memoize checkExistingRelation (useCallback) so the per-item effect does not re-run on every render.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

1 participant