Skip to content

ENG-2258 Create a discourse relation from canvas and associate it with the selected node type pair - #1494

Merged
trangdoan982 merged 7 commits into
eng-2257-add-an-existing-discourse-relation-from-relation-menufrom
eng-2258-create-a-discourse-relation-from-canvas-and-associate-it
Oct 2, 2026
Merged

trangdoan982 merged 7 commits into
eng-2257-add-an-existing-discourse-relation-from-relation-menufrom
eng-2258-create-a-discourse-relation-from-canvas-and-associate-it

Conversation

@trangdoan982

@trangdoan982 trangdoan982 commented Sep 28, 2026 •

Copy link
Copy Markdown
Member

https://entire.io/gh/DiscourseGraphs/discourse-graph/trails/38

Reviewer brief

Stacked on DiscourseGraphs/discourse-graph#1492 (ENG-2257), which must merge first. This PR targets its branch.

  • Result: Create new in the canvas relation menu opens an "Add relation type" dialog. Continue saves the type and links it to the arrow's node-type pair in one save. The menu then lists the new type, and "Relation type created" and "Discourse relation added" toasts appear.

The diagram shows the path from Create new to the refreshed menu.

flowchart LR
  A["Create new<br/>RelationTypeDropdown.tsx"] --> B["CreateRelationTypeModal.tsx<br/>label / complement / color"]
  B --> C{"trimmed, required,<br/>getRelationTypeErrors"}
  C -- error --> B
  C -- ok --> D["createRelationTypeForNodePair<br/>relationTypeUtils.ts"]
  D --> E["push type + ENG-2257<br/>associateRelationTypeWithNodePair<br/>(one save)"]
  E -- save fails --> F["remove added type and relation by id<br/>dialog shows error"]
  E -- ok --> G["dialog closes, menu re-renders,<br/>2 toasts"]
Loading
  • Review focus:
    • The dialog is an Obsidian Modal outside the dropdown's DOM. While it's open, the dropdown ignores its outside-click and Escape listeners. Otherwise a click or Escape in the dialog would dismiss the menu and delete the pending arrow (apps/obsidian/src/components/canvas/overlays/RelationTypeDropdown.tsx).
    • showToast now gives each toast a unique id. tldraw replaces a toast with the same id, and the old ${severity}-${Date.now()} id collided when both success toasts fired in the same millisecond (apps/obsidian/src/components/canvas/utils/toastUtils.ts). This affects every canvas toast.
  • Risk or follow-up:
    • The duplicate check moved from Settings into getRelationTypeErrors in apps/obsidian/src/utils/typeUtils.ts. Settings behaviour is unchanged: exact matching, no trimming.
    • The dialog trims the label and complement before it validates and saves. That is stricter than Settings, so "supports " can't pass as a second "supports".
Verification

Driven in Obsidian 1.13.7 over CDP with real mouse and keyboard input, on the ENG-2256 fixture canvas. Run 2026-09-28T14-48-13, on the final build. The screenshots come from the identical first six rows of run 2026-09-28T14-40-19. ENG-2257's five "Add existing" scenarios also pass on this build.

Scenario Input Expected Actual Pass
Empty pair: Create new → dialog → type listed, both toasts, saved Drag Question → Claim (no types). Create new. Type the label with a stray character and Backspace, then the complement, then pick Blue. Continue. The dialog has the mockup's title, placeholders, Black default, and Cancel / Continue. Typing leaves the canvas alone. The colour list is on top. After Continue, the menu lists only the new type, both toasts appear, and data.json has a local blue type with no status plus a Question → Claim triple. As expected. Canvas shape count and tool unchanged while typing. yes
Empty pair: created type then creates the relation Same flow, then click the new type in the menu The arrow gets the new type id, colour blue, and the label as text. The menu closes. As expected yes
Populated pair: + → Create new Drag Evidence → Claim (supports, opposes). Click +, then Create new in the flyout. Continue. The flyout closes when the dialog opens. The menu lists supports, opposes, and the new type. Both toasts appear. [supports, opposes, v2258 informs], both toasts yes
Validation Continue with empty fields; a spaces-only label; a label only; the label "supports " (trailing space); a new label with an existing complement The five errors in order. The dialog stays open, the inputs are marked, no toast appears, and settings are unchanged. Label is required, Label is required, Complement is required, Duplicate label "supports", Duplicate complement "is supported by". Settings unchanged. yes
Dialog doesn't dismiss the menu Click inside the dialog, then Escape. Reopen and Cancel. Reopen and click the backdrop. Then Escape once more. Each close keeps the menu and the pending arrow. The final Escape dismisses the menu and deletes the arrow. As expected yes
Settings regression Create a type from the canvas. Open Settings → Relation types. Open the new row's colour list. Set its label to "supports" and blur. The row is listed as Blue. The colour list has 13 colours. Both rows show Duplicate label "supports", and nothing is saved. As expected yes
Type added while the dialog is open Create new. Another type "v2258 concurrent" is saved to settings. Submit "v2258 concurrent". Duplicate label "v2258 concurrent". The dialog stays open, and only one type has that label. As expected yes
Escape and backdrop during a pending save Create new, with saveSettings slowed to 1.5s. Continue, then Escape and a backdrop click while saving. The dialog stays open during the save, then closes. The menu lists the new type, and both toasts appear. As expected yes

Screenshots:

Scenario Screenshot
Empty pair: Create new → type listed, both toasts, saved Empty pair: Create new → type listed, both toasts, saved
Empty pair: created type then creates the relation Empty pair: created type then creates the relation
Populated pair: + → Create new Populated pair: + → Create new
Validation: missing or duplicate fields Validation: missing or duplicate fields
Dialog clicks, Escape, Cancel and backdrop keep the menu Dialog clicks, Escape, Cancel and backdrop keep the menu
Settings regression Settings regression

Tests added:

  • apps/obsidian/src/utils/__tests__/typeUtils.test.ts: getRelationTypeErrors (duplicate label, duplicate complement, incomplete types skipped, exact matching).
  • apps/obsidian/src/components/canvas/utils/__tests__/relationTypeUtils.test.ts: createRelationTypeForNodePair (type and triple saved once, rollback on failure, a type saved concurrently survives rollback).
  • Rerun them with pnpm -C apps/obsidian test:unit.

Not verified:

  • The Settings row drives the tab with DOM events, not mouse input. Obsidian 1.13 opens Settings in a separate window, which the CDP mouse can't reach.
  • The dialog's inline "Couldn't save" error is covered by unit tests only. The app run never forced a save failure.
  • Mobile layout. The dialog now lets the colour list overflow the modal. I checked this on desktop only.
  • No single run from a fresh vault covers all of ENG-2255. "Add existing" is covered by the ENG-2257 run and "Create new" by the rows above.

Loom video

https://www.loom.com/share/aa9df4db96844808b6ac51af3b986c6b

Scope check

  • Ran $scope-check against the ENG ticket and final diff.
  • Scope beyond Done When: Dialog validation (required label and complement, no duplicate label or complement). The Settings duplicate check moved into a shared getRelationTypeErrors helper that Settings and the dialog both use.
    • Required now: without it, "Create new" can save blank or duplicate types that the Settings tab then flags on every save, which blocks relation type management there.
    • Anyone affected or consulted: Not documented
    • Decision: Not documented

Standards check

  • Ran $dg-pr-adherence-check against the final diff and PR metadata.

Local delegated full review

  • Ran a comprehensive review of the entire final diff in a subagent with a fresh context. Use $dg-delegated-full-review when no other full-review workflow is available.

Two passes, plus Devin's review. The first found that this branch was behind its base (ENG-2257's c69f392c) and that the create helper's rollback restored a snapshot. Both are fixed: the branch is rebased, and rollback now removes only the added type by id. The second found that the dialog trimmed only for the required check. That is fixed too: the dialog trims before it validates and saves. Devin found that validation used the relation types captured when the dialog opened, and that Escape could close the dialog mid-save. Both are fixed in e360e20a.

🤖 Generated with Claude Code

@supabase

supabase Bot commented Sep 28, 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 Sep 28, 2026 •

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated
discourse-graph Skipped Skipped Oct 2, 2026 8:56pm UTC

Request Review

@linear-code

linear-code Bot commented Sep 28, 2026

Copy link
Copy Markdown

ENG-2258

@trangdoan982
trangdoan982 added this pull request to stack #1495 September 28, 2026 14:44

@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 2 potential issues.

Devin Review

Comment thread apps/obsidian/src/components/canvas/CreateRelationTypeModal.tsx
Comment thread apps/obsidian/src/components/canvas/CreateRelationTypeModal.tsx
@trangdoan982
trangdoan982 force-pushed the eng-2258-create-a-discourse-relation-from-canvas-and-associate-it branch from e360e20 to 2393336 Compare October 2, 2026 19:39
trangdoan982 and others added 7 commits October 2, 2026 16:56
…h the selected node type pair

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3M6B6ERYKXVX44A3Z6TZ8CR
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3M6BDTS4G1NYZCH0QMDPXG8
… blank fields

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3M6VZS14XEE8NRP3SYVAH0K
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3M74W73JE6NCMK1E3EE6WPP
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3M7620BA5K31EABR0WR01QD
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3M7CXKYNM6GGRCNG14QVM0J
…open while saving

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entire-Checkpoint: 01M3M7VZSCCEHXWPEKJX8709X7
@trangdoan982
trangdoan982 force-pushed the eng-2258-create-a-discourse-relation-from-canvas-and-associate-it branch from 2393336 to 6a2e3a4 Compare October 2, 2026 20:56
@trangdoan982
trangdoan982 merged commit 96eaf97 into main Oct 2, 2026
9 checks passed
@trangdoan982
trangdoan982 deleted the eng-2258-create-a-discourse-relation-from-canvas-and-associate-it branch October 2, 2026 20:59

This branch was previously deployed

1 inactive deployment
Preview — 6a2e3a4c Deployed Oct 2, 2026 by vercel[bot]
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