Skip to content

feat(graph): graph-based ontology editing#201

Closed
dgokeeffe wants to merge 13 commits into
databrickslabs:mainfrom
dgokeeffe:feat/agl-energy-demo
Closed

feat(graph): graph-based ontology editing#201
dgokeeffe wants to merge 13 commits into
databrickslabs:mainfrom
dgokeeffe:feat/agl-energy-demo

Conversation

@dgokeeffe
Copy link
Copy Markdown

Summary

  • Detail panel: Click a graph node to open an inline side panel with concept details, edit, and delete actions — no more navigating away from the graph view
  • Context menu: Right-click nodes for View Details / Edit / Create Link / Delete; right-click background to create a new concept; toolbar "New Concept" button gated behind write permissions
  • Click-to-connect: Enter link draw mode from the context menu, click a target node to open the relationship editor with pre-selected source/target and SKOS relationship type picker

All editing actions are gated behind semantic-models READ_WRITE permission. No backend changes — reuses existing CRUD endpoints (POST/PATCH/DELETE /api/knowledge/concepts/{iri}).

Files changed

File Change
ontology-home.tsx Central orchestrator — replaced navigate-away with inline panel/dialog state, wired all new handlers
concept-detail-panel.tsx Added onEdit/onDelete action buttons in panel header
knowledge-graph.tsx Added right-click callbacks, link draw mode with visual indicators, fixed onNodeClick ordering bug
graph-tab.tsx Pass-through for new callback props
NEW graph-context-menu.tsx Custom positioned context menu for canvas right-click (Radix can't wrap canvas elements)

Test plan

  • Click a graph node → ConceptDetailPanel slides in with details; click Edit → editor dialog opens; click related concept → panel navigates
  • Right-click a node → context menu with View Details, Edit, Create Link, Delete
  • Right-click background → context menu with "Create New Concept"
  • Click "New Concept" toolbar button → editor dialog in create mode
  • Context menu "Create Link From..." → pink ring on source, banner appears → click target → LinkEditorDialog with pre-selected source/target
  • Escape or X cancels link draw mode
  • Delete concept → confirm dialog → graph refreshes
  • Read-only users (no semantic-models write permission) → no New Concept button, no edit/delete in context menu or panel
  • Existing expand/collapse, root toggles, filters still work

This pull request was AI-assisted by Isaac.

…ge graph

Rewrite the knowledge graph visualization with W3C RDF/SKOS-native rendering
and add inline editing capabilities — no more navigating away from the graph.

Graph infrastructure:
- Rebuild ForceGraph2D with semantic edge types (skos:broader, rdfs:subClassOf,
  owl:equivalentClass, skos:related, rdf:type, rdfs:subPropertyOf)
- Add concept detail panel with W3C-native property display
- Add edge filter toggles and graph search overlay
- Surface ontology structure (Concept vs Property vs Scheme node types)

Graph-based editing (Phase 1-3):
- Click node → inline detail panel with edit/delete actions
- Right-click node → context menu (View, Edit, Create Link, Delete)
- Right-click background → Create New Concept
- Click-to-connect link draw mode with visual indicators
- All editing gated behind semantic-models READ_WRITE permission
- Reuses existing CRUD endpoints, no backend changes needed

Co-authored-by: Isaac
@dgokeeffe dgokeeffe force-pushed the feat/agl-energy-demo branch from 0f6ab97 to ed77d73 Compare April 11, 2026 06:45
@dgokeeffe
Copy link
Copy Markdown
Author

Test Evidence

All features verified manually via Chrome DevTools MCP on localhost:3000/concepts/graph.

Phase 1: Detail Panel (Click to Inspect)

  • Node click opens detail panel — Clicked AEMO node, ConceptDetailPanel slides in from right showing:
    • W3C type badge (skos:Concept)
    • Label, notation, alt labels ("Australian Energy Market Operator")
    • Definition text
    • skos:related links (AEMO Reporting, Market Prices, Settlement) — clickable to navigate
    • skos:inScheme reference (LuminaEnergyTaxonomy)
    • Edit (pencil) and Delete (trash) action buttons in header
    • Close (X) button
  • Edit button opens ConceptEditorDialog — Clicked Edit in panel header → dialog opens in edit mode with pre-filled fields (label, definition, synonyms, examples)
  • Panel does not navigate away — Graph remains visible and interactive behind the panel

Phase 2: Context Menu + Creation

  • Node right-click shows context menu — Right-clicked "Account Number" node → positioned menu with:
    • View Details
    • Edit Concept
    • Create Link From...
    • Delete Concept (red, with separator)
    • Concept label shown as header
  • Background right-click shows create menu — Right-clicked empty canvas area → menu with "+ Create New Concept"
  • "New Concept" toolbar button — Button visible in header (gated behind READ_WRITE permission)
  • Context menu dismisses on Escape — Verified keyboard dismiss works

Phase 3: Click-to-Connect (Link Draw Mode)

  • "Create Link From..." enters link draw mode — Clicked from context menu → pink banner appears: "Click a target node to create link" with pulsing indicator and cancel (X) button
  • Source node highlighted — Source node gets a pink dashed ring indicator on the canvas
  • Escape cancels link draw mode — Verified Escape key and X button both dismiss the mode cleanly
  • Link draw mode blocks normal click — Clicking any node while in draw mode does NOT open detail panel (intercepted by link draw handler)

Regression Checks

  • Graph renders 85 concepts with force-directed layout
  • Source filter toggles work (2/8 sources selected)
  • Legend items visible (Concept/Property/Scheme, edge types)
  • Zoom controls functional (Zoom In/Out, Fit to View, Reset Layout)
  • No console errors related to the new features

Tested by Isaac via Chrome DevTools MCP

@dgokeeffe
Copy link
Copy Markdown
Author

Screenshots

Screenshots captured during testing (available on request):

# Screenshot Shows
1 01-graph-overview.png Full graph view with 85 concepts, "New Concept" button, source filters, legend
2 02-detail-panel.png ConceptDetailPanel open for AEMO node — W3C properties, related concepts, edit/delete buttons
3 03-node-context-menu.png Right-click context menu on node: View Details, Edit, Create Link From..., Delete
4 04-background-context-menu.png Right-click context menu on empty canvas: "+ Create New Concept"
5 05-link-draw-mode.png Link draw mode active — pink banner with "Click a target node to create link"
6 06-edit-concept-dialog.png ConceptEditorDialog in edit mode — label, definition, synonyms, type fields

@dgokeeffe
Copy link
Copy Markdown
Author

01-graph-overview 02-detail-panel 03-node-context-menu 04-background-context-menu 05-link-draw-mode 06-edit-concept-dialog 06-new-concept-dialog final-fullscreen-labels full-page-graph graph-redesign-legend

@will-yuponce-db will-yuponce-db requested review from a team and removed request for a team April 13, 2026 12:59
Copy link
Copy Markdown
Collaborator

@larsgeorge-db larsgeorge-db left a comment

Choose a reason for hiding this comment

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

Hey Dave, thank you for the work! I have a few questions/remarks at this point:

  • Why switch away from Cytoscape as the renderer? We used ReactFlow2d in the past but then switched to Cytoscape as it has more options available
  • Editing triples is disabled for internal ontologies. We need to still discuss how to handle point or full updates of those, but the UI otherwise makes them read-only. So while you can show the node details, the Edit feature should be more deliberate.
  • The edit dialog has the wrong Z-order, it shows under the dimmed overlay of the main view. You can also see this from your own screenshot.
  • The visual style used is different from the rest of the app. Would be good to align this with the main one.

@will-yuponce-db
Copy link
Copy Markdown
Contributor

Rebasing this branch to capture the changes to transitive packages and trigger CI.

@dgokeeffe dgokeeffe force-pushed the feat/agl-energy-demo branch from 5bf6f72 to ed77d73 Compare May 5, 2026 06:42
David O'Keeffe added 11 commits May 5, 2026 17:02
Resolves the diverging-base situation between PR databrickslabs#201 and main, and addresses
review feedback on the renderer choice.

- Takes main's Cytoscape knowledge-graph.tsx instead of the ForceGraph2D rewrite,
  preserving showDomainBoxes (compound nodes), language-aware label resolution
  (selectedLanguage / resolveLabel), and the existing semantic styling. Reverts
  the Cytoscape→ForceGraph2D regression flagged in PR databrickslabs#201 review.
- Ports the editing UX onto Cytoscape via cy.on() handlers:
    - cxttap on .concept-node → onNodeRightClick (context menu)
    - cxttap on canvas → onBackgroundRightClick (create-new menu)
    - tap branches on linkDrawSource: clicking another node calls onLinkDraw,
      otherwise normal onNodeClick
    - background tap and Escape key both cancel link-draw mode
    - new .link-draw-source stylesheet entry: pink dashed ring on the source
- Drops react-force-graph-2d from package.json (no remaining consumers).
- Regenerates yarn.lock from main.

The renderer-agnostic editing components (concept-detail-panel,
graph-context-menu, edge-filter-toggles, graph-search-overlay) are unchanged.

Co-authored-by: Isaac
…slabs#201)

The original PR's link-draw banner ("Click a target node to create link
from <source>" with pulsing indicator and Cancel X) lived inside the
ForceGraph2D rewrite of knowledge-graph.tsx. Reverting that file to
main's Cytoscape version dropped the banner along with the renderer.

Restored as an overlay in <GraphTab>, where linkDrawSource is already
in scope. Renderer-agnostic — no Cytoscape coupling. Verified via
Chrome DevTools MCP against a live ontos backend with 247 concepts:
right-click → Create Link → banner renders with resolved source
label, X button calls onLinkDrawCancel, Escape and X both clear the
.link-draw-source visual treatment on the source node.

Co-authored-by: Isaac
After the initial port from PR databrickslabs#201's ForceGraph2D rewrite onto main's
Cytoscape, two regressions were caught via Chrome DevTools MCP:

1. Right-click in fullscreen mode did nothing — handlers only wired to
   the main cyRef, not the separate fullscreenCyRef instance that
   <KnowledgeGraph> creates inside its <Dialog>.
2. The link-draw banner (added in 1b1e105 in <GraphTab>) sat at the top
   of the GraphTab container and visually overlapped the source-filter
   legend chips above the graph canvas, AND was hidden behind the
   fullscreen Dialog overlay when in fullscreen mode.

Fixes:
- Extract event-wiring into wireCyHandlers(cy: Core), called from BOTH
  the main and fullscreen <CytoscapeComponent> cy-mount callbacks.
- Use a handlersRef to keep wireCyHandlers referentially stable; that
  way listeners don't churn on every prop change.
- Apply .link-draw-source class to BOTH cy instances in the visual
  treatment effect, with isFullscreen in deps so the new fullscreen
  cy gets the highlight on open.
- Move the link-draw banner from <GraphTab> into <KnowledgeGraph> as a
  small <LinkDrawBanner> helper, rendered inside each cy container's
  relative wrapper. Result: banner sits over the canvas (not above it),
  and shows correctly in both regular and fullscreen views.

Verified end-to-end via Chrome DevTools MCP against a live ontos backend
with 247 concepts:
- Right-click in regular view → context menu (4 items)
- Right-click in fullscreen view → context menu (4 items)
- Create Link From... in either view → banner over canvas + pink
  dashed ring on source node
- Click target node in either view → "Create Link" dialog opens with
  source/target pre-filled and skos:broader default
- Escape and X-button both clear banner and source class

Co-authored-by: Isaac
Addresses PR databrickslabs#201 review point 3 — edit dialog appeared under the
dimmed overlay when opened from inside the fullscreen knowledge graph.

Root cause: shadcn's Dialog defaults to z-50 for both Content and
Overlay. Two open Dialogs (the fullscreen graph and the edit dialog)
collided at z-50, with stacking decided by Portal mount order. From
within fullscreen the edit dialog's overlay sat under the fullscreen
content, hiding the form behind a dim layer.

Fix:
- Add an optional `overlayClassName` prop on `<DialogContent>` so the
  underlying `<DialogOverlay>` can be elevated when nested. Default
  behavior unchanged for all existing dialog usages.
- Concept editor and link editor pass z-[60] for both content and
  overlay, putting them cleanly above the fullscreen Dialog's z-50.

Verified via Chrome DevTools MCP: opened fullscreen, right-clicked a
node, clicked Edit Concept — edit dialog renders above a dim overlay
that correctly covers both the main view and the fullscreen graph.

Co-authored-by: Isaac
Addresses PR databrickslabs#201 review point 2 — Lars: "Editing triples is disabled
for internal ontologies. The Edit feature should be more deliberate."

The backend already gates writes on collection.is_editable (see
update_concept at semantic_models_manager.py:3208), but the frontend
was offering Edit/Delete/Create-Link buttons that would fail server-
side. Frontend now mirrors the gate.

How it works:
- Build a Map<source_context_suffix, is_editable> from the collections
  state already loaded by OntologyHomeView. Concepts carry source_context
  with the prefix stripped ("databricks_ontology"), while collections
  expose the full IRI ("urn:taxonomy:databricks_ontology") — index on
  the bare suffix so they line up.
- isConceptEditable(concept) returns false when the matched collection
  has is_editable=false. Unknown sources fall through to canWrite (the
  backend remains the final guard).
- GraphContextMenu and ConceptDetailPanel both consume the helper:
  Edit / Delete / Create-Link callbacks become undefined for concepts
  from read-only collections, so the menu items / detail-panel buttons
  simply don't render.
- Background right-click ("Create New Concept") and the toolbar
  "+ New Concept" button are unaffected — they create concepts in a
  user-selected editable collection.

Verified via Chrome DevTools MCP:
- Right-click a concept from urn:taxonomy:odcs-ontology (is_editable=
  false) → context menu shows only "View Details"
- Background right-click still shows "Create New Concept"

Co-authored-by: Isaac
Addresses PR databrickslabs#201 review point 4 — Lars: "The visual style used is
different from the rest of the app."

Two specific divergences from the rest of the app:

1. Custom slide-in panel via fixed-positioned divs + a hand-rolled
   bg-black/20 overlay, while the rest of the app (e.g.
   <CommentSidebar>) uses shadcn <Sheet>. Different animation, different
   overlay opacity, different keyboard/focus behavior.

2. Type badges on the panel header used inline rgba/hex values
   (rgba(139,92,246,0.12), #8b5cf6, etc.), bypassing the Tailwind palette
   and dark-mode tokens used elsewhere.

Changes:
- Wrap the panel content in <Sheet>/<SheetContent side="right">. Removes
  the custom overlay, manual close X (Sheet provides one), and z-index
  juggling — Sheet's portal + animation are handled by Radix.
- Move Edit/Delete buttons to right-12 to leave Sheet's standard right-4
  close-button slot free.
- Replace W3C_TYPE_STYLE (inline rgba/hex) with W3C_TYPE_BADGE_CLASS and
  W3C_TYPE_STRIPE_CLASS that map to Tailwind utility classes
  (bg-emerald-500/10, text-blue-500, etc.). Theme-aware, no inline
  styles, identical visual outcome.

Verified via Chrome DevTools MCP — panel mounts as Sheet, type badge
rendered with classes (no inline style attribute), stripe colored via
Tailwind class, Sheet's bg-black/80 overlay matches the app's other
slide-in panels.

Co-authored-by: Isaac
The Sheet conversion in 8da7956 surfaced two Radix accessibility
warnings (Sheet wraps Dialog primitives, which require a Title):

  ⚠️ DialogContent requires a DialogTitle for the component to be
     accessible for screen reader users.
  ⚠️ Missing `Description` or `aria-describedby={undefined}` for
     {DialogContent}.

Fixes:
- The visible H1-style concept name is now a <SheetTitle> with the
  same Tailwind classes (text-xl font-bold pr-8 leading-tight). The
  base SheetTitle's text-lg font-semibold is overridden by tw-merge,
  so the visual is unchanged.
- The loading state ("Loading...") gets a sr-only <SheetTitle> so the
  Sheet always has a screen-reader-discoverable name.
- Set aria-describedby={undefined} on <SheetContent> to opt out of the
  description requirement — there's no single sentence that fits a
  panel scrolling through synonyms, definitions, hierarchies, etc.

Verified via Chrome DevTools MCP — both warnings cleared, panel still
mounts as Sheet with aria-labelledby pointing at the SheetTitle, X
close still functional, open/close cycles clean.

Co-authored-by: Isaac
In-flight edits in <ConceptEditorDialog> were pure React state — closing
the dialog (Cancel / Escape / X) or refreshing the page silently lost
everything. Adds two layers of safety:

1. **sessionStorage autosave**: every field change writes the form to
   sessionStorage under a per-concept key
   (ontos.concept-editor.draft.<iri-or-new:collection>). Survives page
   refresh and back/forward nav; cleaned up on tab close (so drafts
   don't accumulate). On dialog open, an existing draft is restored
   transparently.

2. **Confirm-discard guard**: closing the dialog with unsaved changes
   pops a native confirm("Discard unsaved changes?"). Skipped during
   page unload (Radix fires onOpenChange on unmount; the browser's own
   beforeunload UX handles tab close instead).

Subtle ordering bugs caught in test:
- The existing [concept] effect (deps: concept, collection, open)
  re-fires every time the dialog opens and was clobbering the
  restored draft because it ran later in declaration order. Fixed by
  short-circuiting that effect when a draft exists for the current
  draftKey.
- Autosave on the same render that restores would otherwise see stale
  formData against the freshly-updated cleanSnapshotRef and overwrite
  the draft with empty data. Guarded with skipNextAutosaveRef.

Verified via Chrome DevTools MCP:
- Type in label → sessionStorage populated immediately
- Reload page → storage survives, no spurious confirm prompt
- Reopen dialog → label pre-filled, storage NOT overwritten with empty
- Click Cancel on dirty form → confirm fires, accept clears draft and
  closes, dismiss keeps dialog open

Co-authored-by: Isaac
…tions

Following PR databrickslabs#201 review feedback comparing visual feel to the original
ForceGraph2D rewrite. Adds polish to the existing Cytoscape view to
get closer to that aesthetic without changing renderer:

- **Animation transitions**: nodes and edges now declare
  `transition-property` + `transition-duration` (200ms / 180ms ease-out)
  so hover/select state changes scale smoothly instead of snapping.
- **Drop shadows on concept nodes**: 8px blur in the node's own color,
  alpha tuned per theme (0.5 dark, 0.25 light). Reads as a soft glow
  on dark, a soft drop on light.
- **Hover halo**: overlay-color/overlay-opacity/overlay-padding
  produces an outward color ring around the hovered node — the
  characteristic "force graph" hover-glow effect.
- **Selected halo**: same overlay treatment but in gold (#FFD700) for
  the selected state, building on the existing gold ring.
- **Property nodes** get matching hover/selected halos.
- **Edge transitions**: width / opacity / color animate on hover
  instead of snapping to gold.
- **Cose layout tuning**: longer ideal edges (80 → 110), more
  repulsion (400k → 600k), more iterations (1000 → 1500), gentler
  cooling (0.95 → 0.96), eased animation. Result is more breathing
  room and a more organic settled-look.
- **Slight node-size bumps**: concept 24 → 26, property 20 → 22 base;
  hover sizes scale up proportionally.

Polish is most visible at interactive zoom levels (clusters / single-
node neighborhoods). At fit-to-screen with 247 concepts the nodes are
still small dots — that's a function of node count, not styling.

Co-authored-by: Isaac
Adds cytoscape-fcose ("fast compound spring embedder") as a layout
extension and makes it the default in place of the built-in cose. Same
underlying force-directed model, but with substantially better default
aesthetics, faster convergence, and gentler handling of compound
domain nodes — closer to the look of dedicated force-graph libraries
without leaving Cytoscape.

Concrete changes:
- package.json: add cytoscape-fcose ^2.2.0 (run `yarn install` to fetch).
- knowledge-graph.tsx:
  - Register the extension via cytoscape.use(fcose). The call is
    idempotent so HMR / Strict-mode double-mounts are safe.
  - Extend LayoutType union with 'fcose' and add 'fcose' as the default
    initial layout state. Existing 'cose' remains selectable as
    "Force-Directed (legacy)" for comparison.
  - Add fcose case to getLayoutConfig with sensible parameters:
    quality='proof' (full convergence), randomize=false (use current
    positions for stable re-layouts), animate='end' (single transition
    to final positions), nodeRepulsion=8000, idealEdgeLength=90,
    edgeElasticity=0.45, gravity=0.25, packComponents=true.

Build / install note: the dependency is registry-neutral — package.json
declares the version range only, and yarn.lock will resolve it via
whatever registry yarn sees at install time. Locally you can use the
internal proxy (`yarn config get registry`); CI and Databricks Apps
deploys use the default public registry.

Co-authored-by: Isaac
The first fcose config produced a degenerate diagonal stripe inside
each compound domain — caused by tile=false + randomize=false +
quality='proof' interacting badly with showDomainBoxes. Fixed by
returning to fcose's natural defaults for compound handling:

- tile=true (default): pack compound children naturally instead of
  letting them snake corner-to-corner
- randomize=true: let fcose pick a fresh starting state per layout run
  so it doesn't lock onto whatever the previous layout left behind
- quality='default': converges fast enough on ~250 nodes; 'proof' was
  over-converging into local minima for our compound structure
- nodeRepulsion 8000 → 4500: less aggressive separation gives tighter
  intra-domain clustering
- Added tilingPaddingVertical/Horizontal=12 for breathing room
  between tiled children inside each domain box

Also locks in the yarn.lock entries for cytoscape-fcose ^2.2.0 and its
transitives (cose-base, layout-base). The lock URLs all point at the
public registry (registry.yarnpkg.com), keeping CI/deploy builds
registry-neutral as discussed.

Verified visually via Chrome DevTools MCP: each domain compound
contains an organic force-distributed cluster of its concept nodes;
inter-domain edges visible as faint connecting lines.

Co-authored-by: Isaac
@dgokeeffe
Copy link
Copy Markdown
Author

Hey Lars — thanks for the review. Each point addressed below; commits referenced are on this branch (feat/agl-energy-demo):

1. Why switch away from Cytoscape? → reverted

You're right — went with ForceGraph2D for the visual polish but didn't realise Cytoscape already covered the capabilities I'd need (compound nodes for showDomainBoxes, dagre/cose layouts, cytoscape-edgehandles-style click-to-connect via cy.on('cxttap', …)).

Reverted to Cytoscape in c1e3889 (merge commit that brings main in and takes main's Cytoscape knowledge-graph.tsx over the rewrite). The editing UX was ported on top via cy.on() handlers — cxttap for the right-click menu, branch-on-linkDrawSource for click-to-connect, .link-draw-source class for the pink dashed-ring source highlight, Escape and X both cancel.

Subsequent fixes:

  • 3010b9d — wired the same handlers to fullscreenCyRef (was a regression: right-click did nothing in fullscreen) and moved the link-draw banner inside <KnowledgeGraph> so it sits over the canvas in both regular and fullscreen views (was overlapping the toolbar legend before).
  • 1b1e105 — restored the banner overlay itself (lived inside the original ForceGraph2D file and dropped along with it).

I also went a step further on the look since "doesn't look as nice as before" was the implicit fairness check:

  • ce3c479 — added animation transitions, shadow-blur per node in its own colour, overlay-color/overlay-padding halo on hover/selected, edge transitions on width/opacity. Tuned cose for more breathing room.
  • 50e9cf5 + 0579522 — added cytoscape-fcose extension (modern force-directed layout — quality:'default', compound-aware tiling). Now the default; cose kept as "Force-Directed (legacy)" for comparison.

2. Editing should be more deliberate for internal ontologies → done

Backend already gates writes on collection.is_editable (semantic_models_manager.py:3208) but the frontend was offering Edit/Delete/Create-Link buttons that would 4xx server-side. Now mirrored client-side in 67f4ea2:

  • <OntologyHomeView> builds a Map<source-context-suffix, is_editable> from the already-loaded collections state.
  • isConceptEditable(concept) returns false when the matched collection has is_editable=false.
  • <GraphContextMenu> and <ConceptDetailPanel> consume the helper — Edit / Delete / Create-Link callbacks become undefined for concepts from read-only collections, so those menu items / detail-panel buttons simply don't render.

For internal taxonomies (urn:taxonomy:databricks_ontology etc.) right-click now shows only "View Details". Background right-click ("Create New Concept") and the toolbar + New Concept button are unaffected — those let the user pick an editable collection in the editor.

3. Edit dialog Z-order → fixed

Root cause was two <Dialog>s at z-50 (the fullscreen knowledge-graph dialog and the edit dialog) competing on Portal mount order. Fixed in ed9040e:

  • Added an overlayClassName prop to base <DialogContent> (additive — no behaviour change for existing dialogs).
  • Concept editor and link editor pass z-[60] for both content and overlay, putting them cleanly above the fullscreen Dialog's z-50 stack.

Verified via Chrome DevTools: opening Edit from inside fullscreen now puts the form above a dim overlay that correctly covers both the main view and the fullscreen graph.

Bonus improvement layered on top — 84e012d added <SheetTitle> + aria-describedby={undefined} to silence Radix a11y warnings introduced by the Sheet conversion (see #4).

4. Visual style alignment → done

Two specific divergences:

  • <ConceptDetailPanel> was a hand-rolled slide-in panel (fixed top-0 right-0 … with custom bg-black/20 overlay) instead of using shadcn <Sheet>. Different animation, different overlay opacity, different focus management vs. e.g. <CommentSidebar> which uses Sheet.
  • W3C type badges used inline rgba(139,92,246,0.12) / #8b5cf6 etc., bypassing the Tailwind palette and dark-mode tokens.

Fixed in 8da7956:

  • Wrapped panel content in <Sheet><SheetContent side="right">. Removes the custom overlay, manual close X, and z-index juggling — Sheet's portal + animation are handled by Radix.
  • Edit/Delete buttons moved to right-12 to leave Sheet's standard right-4 close-button slot free.
  • Replaced W3C_TYPE_STYLE (inline rgba/hex) with W3C_TYPE_BADGE_CLASS and W3C_TYPE_STRIPE_CLASS mapping to Tailwind utility classes (bg-emerald-500/10, text-blue-500, etc.). Theme-aware, no inline styles, identical visual outcome.

If there are more specific style divergences you spotted, happy to address — these were the most obvious ones.

Plus: editor draft persistence + confirm-discard guard (2db33fe)

Not in your review but caught during testing — closing the editor (Cancel / Escape / X / refresh) was silently dropping in-flight edits. Now:

  • Every form change is mirrored to sessionStorage under a per-concept key.
  • On dialog open, an existing draft is auto-restored.
  • Closing with unsaved changes pops a window.confirm("Discard unsaved changes?"). Skipped during page unload (Radix fires onOpenChange on unmount; the browser's own beforeunload UX handles tab close).
  • Drafts cleaned from storage on successful save.

Verification

End-to-end tested via Chrome DevTools MCP against an ontos backend with 247 concepts:

  • Right-click a concept from urn:taxonomy:odcs-ontology → only "View Details" appears
  • Click a concept → <Sheet>-based detail panel slides in with proper bg-black/80 overlay
  • Right-click → "Create Link From..." → banner over canvas + pink dashed ring on source → click target → "Create Link" dialog opens with source/target/skos:broader pre-filled
  • Open fullscreen → right-click works → Edit dialog opens above fullscreen overlay
  • Type in editor → refresh → reopen → field pre-filled from sessionStorage draft
  • Cancel with unsaved changes → confirm prompt → accept clears, dismiss keeps editor open

App also redeployed to a personal sandbox workspace and verified RUNNING with all 4 resources bound (sql-warehouse, database, serving-endpoint, volume).

Re-requesting review when you have a moment 🙏

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.

3 participants