Skip to content

feat: add selectable graph layouts#82

Merged
paolino merged 1 commit intomainfrom
012-layout-picker
Apr 23, 2026
Merged

feat: add selectable graph layouts#82
paolino merged 1 commit intomainfrom
012-layout-picker

Conversation

@paolino
Copy link
Copy Markdown
Contributor

@paolino paolino commented Apr 23, 2026

Summary

This PR adds user-selectable graph layouts to the shared viewer and wires the feature through the full stack: viewer state, persistence, query/view metadata, Cytoscape layout engines, schema validation, tests, and docs.

Closes #39.

The feature now supports these layout IDs:

  • fcose
  • elk
  • cola
  • dagre
  • concentric

The control is exposed in the viewer toolbar, relayouts the current graph in-session, and persists the user's explicit choice per repo.

What Changed

1. Added an explicit layout model in PureScript

A new Layout module defines the canonical layout IDs, labels, parsing, default selection, and the source of the current effective layout (SavedExplicit, ViewDefault, Fallback).

This keeps layout precedence explicit in PureScript instead of burying it in the Cytoscape FFI.

2. Extended viewer state and behavior

The viewer now tracks:

  • the active layout
  • why that layout is active

Behavior changes:

  • on initialization, the viewer restores a saved explicit layout preference when present
  • when the user picks a layout, the graph relayouts without reloading data
  • when a legacy view or a query-backed view becomes active, authored defaults apply only if there is no saved explicit choice
  • when clearing a query or jumping between tutorial/query/view flows, the effective layout is recomputed instead of silently drifting
  • selection styling is replayed after rerenders so node/edge focus survives layout changes

3. Added dedicated layout persistence

This PR deliberately does not change the existing title-keyed persistence for selected node, depth, and tutorial progress.

Instead it adds a separate localStorage entry:

  • graph-browser:layout:<identity>

The identity is derived to stay repo-scoped in app mode:

  • parse owner/repo from raw GitHub baseUrl when possible
  • otherwise fall back to baseUrl
  • otherwise config.sourceUrl
  • otherwise config.title

That keeps explicit layout choices repo-specific without broadening the scope of the older persistence contract.

4. Added authored layout defaults to both view mechanisms

Both view entry points now accept an optional layout field:

  • query-backed views in data/queries.json
  • legacy view JSON files in data/views/*.json

Invalid layout strings are ignored at decode time rather than failing the whole file.

5. Added Cytoscape layout engines and runtime switching

The bundle now registers:

  • cytoscape-fcose
  • cytoscape-elk
  • cytoscape-cola
  • cytoscape-dagre

The FFI keeps one active layout concept and uses it for both fresh renders and direct relayout requests. Each layout gets conservative default options tuned for this viewer so switching is immediate and doesn't require data reload.

6. Updated schemas, prompt-builder context, and README

The JSON schemas now validate the optional layout field for both query-backed and legacy views.

The prompt-builder guidance and README now document:

  • supported layout IDs
  • where to author default layouts
  • the fact that explicit user choice overrides authored defaults after the first selection

7. Added and extended tests

The PR adds decode coverage for both query-backed and legacy view layout metadata, while preserving existing integration tests over the self-graph.

Design Choices

Precedence rule

The effective layout order implemented here is:

  1. saved explicit repo layout
  2. authored default on the active view
  3. fcose fallback

This matches the spec and keeps authored defaults useful for first-time visitors without overriding a deliberate user choice.

Separate persistence instead of mutating PersistedState

I kept layout preference storage separate from the older selected-node/depth/tutorial restore path. Re-keying the older persistence model would have expanded the risk of this change well beyond the layout feature.

Canonical repo identity in app mode

The spec work initially described baseUrl directly as the primary identity input. During implementation I tightened that to canonical owner/repo when baseUrl is a raw GitHub URL, so branch previews share the same repo-scoped layout preference instead of fragmenting by branch ref.

The spec artifacts in specs/012-layout-picker/ were updated to reflect that implementation decision.

Files to Review

Core implementation:

  • src/Layout.purs
  • src/Viewer.purs
  • src/Viewer/Controls.purs
  • src/Persist.purs
  • src/FFI/Cytoscape.js
  • src/bootstrap.js

Data/model/schema:

  • src/Graph/Query.purs
  • src/Graph/Views.purs
  • schema/query-catalog.schema.json
  • schema/view.schema.json

Tests and docs:

  • test/Test/QueryCatalog.purs
  • test/Test/ViewDecode.purs
  • README.md
  • specs/012-layout-picker/*

Verification

Executed locally:

  • nix develop -c just test
  • nix develop -c just bundle-app
  • nix develop -c just bundle-lib

Results:

  • tests passed (30/30)
  • app bundle succeeded
  • lib bundle succeeded

Follow-up

I did not deploy a preview in this PR because the repo does not define a concrete surge task or checked-in preview workflow. If we want a Surge preview here, that should be added as an explicit, repeatable command rather than inferred ad hoc.

@paolino paolino added the enhancement New feature or request label Apr 23, 2026
@paolino paolino self-assigned this Apr 23, 2026
@paolino
Copy link
Copy Markdown
Contributor Author

paolino commented Apr 23, 2026

@paolino paolino force-pushed the 012-layout-picker branch from eb273c2 to daca576 Compare April 23, 2026 17:44
@paolino paolino merged commit 3b3346f into main Apr 23, 2026
1 check 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

User-selectable graph layout algorithms

1 participant