Skip to content

feat(web): redesign Model Canvas as an ERD (compact/detailed views, draggable nodes, brand styling) - #1476

Merged
laskevych merged 5 commits into
OWOX:mainfrom
ikrasovytskyi:feat/model-canvas-erd-redesign
Jul 30, 2026
Merged

feat(web): redesign Model Canvas as an ERD (compact/detailed views, draggable nodes, brand styling)#1476
laskevych merged 5 commits into
OWOX:mainfrom
ikrasovytskyi:feat/model-canvas-erd-redesign

Conversation

@ikrasovytskyi

@ikrasovytskyi ikrasovytskyi commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Preview

0730.1.mov

Summary

Redesigns the Data Marts Models canvas into a proper ERD, bringing its look-and-feel in line with the standalone OWOX Model Canvas (owox-model-canvas, Apache-2.0). Both canvases already use React Flow (@xyflow/react), so this is a rendering/interaction upgrade rather than a rewrite — the existing data wiring, dagre layout, highlight, search and filters are all preserved.

The previous canvas rendered each mart as a fixed 240×74 box showing only a title and a field count, with orthogonal (elbow) edges and no way to inspect fields, tell mart types apart, or move nodes.

What changed

Node cards

  • Two view modesCompact (default: header + type badge + field count) and Detailed (adds an ERD body). Toggle in the canvas settings popover; persisted per browser.
  • Detailed cards show typed field rows with a primary-key indicator, primary-keys-first ordering, and hidden-for-reporting fields dimmed. Collapsed to 4 rows by default with a "+N more fields" that expands in place (with "Show less") — it no longer navigates away.
  • Definition-type accent + badge (VIEW / SQL / TABLE / PATTERN / CONNECTOR), a published/draft status dot, and tidied padding.

Interaction

  • Nodes are now draggable (nodesDraggable + onNodesChange); drag positions persist between layout runs.
  • Removed the background grid and the React Flow attribution badge (proOptions.hideAttribution).

Edges

  • Replaced dagre elbow routing with pure React Flow bezier curves (no angled corners).
  • Recolored to the OWOX brand blue (--primary, #0084ff) to match primary actions. Scoped to the model canvas — the edit-screen RelationshipCanvas is untouched.
  • Added an N:1 / 1:1 cardinality badge alongside the existing join-field label.

Implementation notes

  • Field/definition-type data is not returned by the GET /model-canvas/data-marts list endpoint, so nodes are enriched client-side from GET /data-marts/{id} (which already exposes schema.fields + definitionType) in bounded-concurrency batches. A failed detail fetch leaves that node compact instead of failing the whole canvas. Alternative: enrich the list endpoint server-side to avoid the N extra requests — happy to switch to that if preferred.
  • Node height is a pure function of its data + view mode, so the dagre layout (computed before render) and the rendered node agree. Collapsed height is used for layout; an expanded Detailed card may overlap the card below until dragged — same behaviour as owox/models.
  • New model/erd-node.ts centralises the accent palette and sizing/geometry helpers.

Attribution

The visual/interaction design is ported from owox/models (Apache-2.0, © OWOX, Inc.), adapted to this app's UI kit and theme tokens (works in light and dark).

Testing

  • type-check, ESLint, and the model-canvas unit suite (52 tests) all pass.
  • Manually verified against a local BigQuery storage: compact default, view toggle, in-place expand, drag (node transform confirmed to move), blue bezier edges, N:1 labels, no attribution badge.

Known trade-offs / possible follow-ups

  • Bezier edges take the shortest path between handles, so in dense layouts a line can pass under a card (the old elbow routing avoided this, at the cost of the corners). smoothstep edges are a node-avoiding middle ground if desired.
  • Expanding a Detailed card doesn't re-run layout; could optionally re-flow on expand.
  • Relationship-label modes could be extended (all / defined / undefined / hidden) as in owox/models; this PR keeps the existing "Show join fields" toggle.
  • A dedicated dark-mode polish pass hasn't been done (it relies on theme tokens).

How to try it

  1. npm install
  2. Run the web app and the backend, open Data Marts → Models, pick a storage.
  3. Use the settings (gear) to switch between Compact and Detailed, drag cards, and expand fields.

ikrasovytskyi and others added 3 commits July 29, 2026 03:18
Port the OWOX Model Canvas (owox/models, Apache-2.0) look into the Data
Marts model canvas. Node cards now show a definition-type accent stripe +
badge (VIEW / SQL / CONNECTOR / TABLE / PATTERN), a draft marker, and an
ERD body: primary-key rows (keys first), typed field rows, and a '+N more'
affordance that opens the Data Mart. Edges gain an N:1 / 1:1 cardinality
badge next to the join-field label.

definitionType + fields are enriched client-side from the data-mart detail
endpoint (the /model-canvas/data-marts list omits them) in bounded-
concurrency batches; a failed detail fetch leaves that node compact. Node
height is a pure function of field count so the dagre layout and the
rendered node stay in sync.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…expand

Address review feedback to match the owox/models canvas UX:
- Default to a compact card (header + type badge + field count); field rows
  now appear only in the new 'Detailed' (ERD) view, toggled from settings.
- Make nodes draggable (nodesDraggable + onNodesChange) with drag positions
  preserved between layouts — cursor-grab affordance, action buttons marked
  nodrag.
- '+N more fields' now expands the card in place (keys-first, collapsed at 4
  rows) with a 'Show less' toggle, instead of opening the Data Mart.
- Tidy card padding, header accent stripe + published/draft status dot.
- Remove the canvas background grid.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Edges now render in OWOX brand blue (#0084ff, --primary), matching the
  New Data Mart button, instead of steelblue (scoped to the model canvas;
  the edit RelationshipCanvas is untouched).
- Replace dagre elbow routing with pure React Flow bezier curves — no more
  angled corners in the join lines.
- Hide the React Flow attribution badge (proOptions.hideAttribution).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@ikrasovytskyi
ikrasovytskyi requested a review from kalnik-a-a July 29, 2026 09:12
@laskevych
laskevych self-requested a review July 29, 2026 16:36
@laskevych laskevych self-assigned this Jul 29, 2026
@laskevych laskevych added the enhancement New feature or request label Jul 29, 2026
@laskevych

Copy link
Copy Markdown
Contributor

Hi @ikrasovytskyi! 👋

Thank you so much for your interest in the project and for this contribution — we really appreciate the time and care you put into this PR, including the detailed description, testing notes, and trade-off analysis.

We'll review your proposal and get back to you soon.

- Render the canvas immediately from the lightweight list data and run
  the per-mart detail enrichment as a follow-up query, so first paint no
  longer waits for N sequential detail batches; results merge by id.
- Restore parallel-edge separation: distinct joins between the same mart
  pair bow their bezier curves apart again instead of overlapping.
- Derive the edge cardinality badge (1:1 / N:1 / 1:N) from declared
  primary keys covered by the join, hiding it when uniqueness cannot be
  proven, instead of guessing from edge direction.
- Color minimap nodes by definition-type accent.
- Drop dead elbow-routing code (route/labelPosition edge data,
  buildRoundedPath) and rename rounded-path.ts to path-point.ts.
- Announce the node status dot to assistive technology.
- Add unit tests for erd-node geometry helpers, cardinality inference,
  and in-place field expand/collapse.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@laskevych

Copy link
Copy Markdown
Contributor

Hi @ikrasovytskyi! 👋

Thanks again for this contribution — we've reviewed the PR, and the new ERD design looks great. The declared checks were all honest (type-check, ESLint, and the test suite passed exactly as described), and the detailed PR description with trade-off notes made the review a pleasure.

Since you enabled "Allow edits by maintainers", we've pushed a commit (d964dff) on top of your branch that addresses the review findings, so your work lands faster. Here's what it changes and why:

1. Non-blocking detail enrichment. The per-mart detail fetches ran inside the main queryFn, so the canvas stayed blank until all GET /data-marts/{id} batches finished — even in Compact mode, which doesn't need fields at all. The enrichment now runs as a follow-up query: the canvas renders immediately from the lightweight list data and upgrades in place (badges/fields appear) once details arrive, merged by id so a base refetch can't resurrect stale titles.

2. Restored parallel-edge separation. The switch to pure getBezierPath dropped the bowOffset handling, so two distinct joins between the same pair of marts rendered as identical overlapping curves with stacked labels. We kept your smooth bezier look but reinstated the bow for parallel edges (label placed at the curve midpoint).

3. Primary-key-based cardinality. The markerStart ? '1:1' : 'N:1' heuristic labeled every ordinary join N:1, including M:N ones. Since the enrichment now gives us each mart's primary keys, the badge is derived from them: a side is unique when the join covers its full PK (model/graph/edge-cardinality.ts). When uniqueness can't be proven, the badge is hidden — no badge beats a guessed one.

4. Cleanup + small wins. Removed the now-dead elbow-routing data (route/labelPosition, buildRoundedPath; rounded-path.tspath-point.ts), colored the minimap nodes by definition-type accent (your comment in erd-node.ts promised it 🙂), made the Draft/Published status dot accessible to screen readers, and fixed a MiniMap generic typing issue that broke tsc -b in the full build. Also added unit tests for the ERD geometry helpers, cardinality inference, and the in-place expand/collapse.

Your idea of enriching the list endpoint server-side is a good one — we'd like to keep it as a follow-up rather than grow this PR.

Please take a look at the commit when you have a moment — happy to discuss any of it. Once CI is green we'll move forward with the merge. Thanks again for the quality contribution! 🚀

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@laskevych
laskevych merged commit c6c0d7b into OWOX:main Jul 30, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Development

Successfully merging this pull request may close these issues.

2 participants