Repository navigation
Relationships modal renders a full section per declared type, so an empty node shows six 'Add' buttons and no data #2385
Description
Problem
The relationships modal is disproportionate to what it shows. On a new adr node with six declared relationships and no edges yet, it renders:
- Six section headers, every one reading "0 items"
- Six identical "+ Add" buttons, one per empty section
- A scrolling modal in which nothing at all is data — it is entirely scaffolding
- Three ways to dismiss it: Done, Close, and the ✕
The component is 1044 lines (relationship-viewer-modal.svelte). The weight is mostly structural, not incidental.
The empty sections are deliberate — and that is the thing to revisit
relationship-viewer-modal.svelte:126-127:
shows every group — including a declared-but-empty outbound relationship — so its Add control can create the first edge
The reasoning is sound in isolation: an empty relationship needs somewhere to add its first edge. But it means the modal's size scales with the schema's declared relationships rather than with the node's actual data, so a richly-modelled type is at its most overwhelming exactly when it is least useful — before any edges exist.
Inbound relationships: show them, do not edit them from here
Two sections carry ← (inbound) arrows — "Superseded By" and "Related From" — and both currently offer an identical "+ Add" button. They should not.
The asymmetry is real, not cosmetic. An outbound edge (supersedes → adr) is declared on this node's schema and owned by this node. An inbound one (superseded_by) is the same physical edge viewed from the other end — declared on the other ADR's schema, owned by that node. There is one row in the relationship table; this panel renders it twice, once per direction.
So "Add" under Superseded By means: find some other ADR and create a supersedes edge on that node, pointing here. Three problems with offering that:
- It misrepresents ownership. The resulting edge is not on this node's schema-declared relationships; it lives on the other node. Nothing in the UI indicates the write lands elsewhere.
- The picker semantics silently invert. Outbound asks "pick a target". Inbound asks you to pick a source — the node that will point at you. Same widget, opposite meaning, no label distinguishing them.
- It cannot always work. An inbound Add requires the other type's schema to declare the forward relationship. That holds here (
supersedesis declared onadr), but for a cross-type inbound group whose source schema lacks the forward edge, Add has nothing to write and must fail — with no way for the user to have anticipated it.
Showing inbound edges is still valuable. "Which ADRs supersede this one?" is precisely the question a graph should answer, and it is the payoff for modelling with relationships instead of text arrays. Read-only display keeps that value without the confusion.
Where the edge should be created instead: from the node that owns it. Open the superseding ADR and add supersedes → ADR-7. That reads correctly and writes where the data lives.
Worth adding: make inbound rows navigable — click through to the owning node, where the edge can be edited properly. That preserves discovery without pretending this panel can edit it.
Proposed direction## Proposed direction
Simple per-row controls, and let content drive the layout:
- Add — one control per relationship type, as today, but reachable without the section standing open and empty
- ✏️ edit — per row, for edge properties (see below)
- ❌ remove — per row
Edit must stay — edges carry properties. An earlier revision of this issue suggested dropping ✏️ on the grounds that an edge is just a pointer. That is wrong: relationships support edge properties, and editing them is the reason the mode exists. EdgeField is a first-class type (packages/nodespace-types/src/schema.rs:197), declared per relationship via SchemaRelationship.edge_fields (:242), written through --edge-data on the CLI (references/cli.md:209) and updateEdgeProperties in this modal (:418).
This is about to matter concretely: the collection↔person relationship will carry RBAC — ownership, read-only, modify. Those are edge properties, and they must be editable per row.
So ✏️ is not optional, and the redesign must keep per-row property editing intact. What can go is the modal-wide mode toggle that currently gates it: editing one edge's properties should not flip the entire panel into a different state. Per-row drafts and immediate persistence already work (:416-418, :511) — the mode wrapper is the removable part, not the capability.
Note a remove control already exists (removeRow, :426) — it is gated behind an "Edit" toggle that flips the whole modal into an editable mode (:11). Much of the ask is therefore about removing that mode wrapper and surfacing the controls inline, not building new capability.
Collapse empty sections
The highest-value change. Empty relationship types should not each occupy a full section with a header, a count and a button. Options, in rough order of preference:
- Show only relationship types that have edges; put every empty type behind one "+ Add relationship" control that asks which type
- Collapse empty types to a single compact line each, expanding on click
- Group all empty types under one collapsed "No relationships yet (6 types available)" disclosure
Any of these turns the screenshot from six empty sections into one line.
Dismissal
Done, Close and ✕ all dismiss the same modal, which holds no unsaved state — mutations apply immediately (confirmAdd, removeRow). Keep one. If the "Edit" mode wrapper goes away, "Done" loses its meaning too.
Acceptance criteria
- A node with no relationships does not render one section per declared type
- Adding a first edge for a type with none is still reachable, in at most one extra interaction
- Per-row remove is available without switching the modal into a separate edit mode
- Per-row edit of edge properties is preserved — this is required for the collection↔person RBAC work, not optional polish
- Editing one row's properties does not switch the whole modal into a separate mode
- Rows for relationships that declare no
edge_fieldsdo not show an edit control with nothing to edit - Where a relationship declares
edge_fields, a row's current property values are visible without entering an edit mode first - Inbound (reverse) groups are read-only — no Add, no per-row edit or remove
- Inbound groups are visually distinguishable from outbound at a glance, not only by arrow direction
- Inbound rows navigate to the node that owns the edge, where it can be edited
- Empty inbound groups follow the same collapsing rule as empty outbound ones — with no Add to justify a standing section, they have even less reason to occupy one
- Exactly one dismiss control remains
- The modal fits without scrolling for a typical node — the ADR case with six declared types and no edges is the benchmark
- Existing behaviour preserved: immediate persistence, per-row drafts not lost when another row's add completes (
:511), error surfacing
Context
Observed on a real adr schema created during this session — four outbound and two inbound relationships, no edges yet. The schema itself is reasonable; the panel's response to it is what needs work.
Activity
malibio commentedon Sep 7, 2026
Frontend baseline: 232 test files passed, 4863 tests passed.