Skip to content

Add styling import / export / reset UI#1824

Open
jkemmererupgrade wants to merge 6 commits into
aws:mainfrom
jkemmererupgrade:feature/styling-import-export
Open

Add styling import / export / reset UI#1824
jkemmererupgrade wants to merge 6 commits into
aws:mainfrom
jkemmererupgrade:feature/styling-import-export

Conversation

@jkemmererupgrade

Copy link
Copy Markdown
Contributor

Description

Slice 2 of the 3-slice split of #1589 per @kmcginnes's review on that PR. This is the Styling Import / Export / Reset UI. Stacks on slice 1 (#1777) because it relies on the lucide: storage convention slice 1 introduces.

Adds three buttons to Settings → General:

  • Export Styling — downloads the current node and edge styling as a pretty-printed JSON file (graph-explorer-styling.json, 2-space indent). Icons are written as symbolic references ("iconUrl": "lucide:plane") so the file is human-readable and version-controllable.
  • Import Styling — accepts a styling JSON, validates it via Zod, applies it as the active styling, and stores it as the reference baseline. The schema accepts a shorthand "icon": "" field that gets converted to "iconUrl": "lucide:" on import.
  • Reset All Styling — resets every node and edge style. If a styling file has been imported this session, restores to those values; otherwise reverts to hardcoded defaults.

The per-type Reset to Default button on NodeStyleDialog now also restores to the imported baseline (when one exists), via a new defaultStylingAtom reference copy and a shared mergeDefaultsIntoUserStyling helper.

The shared toJsonFileData utility gets an optional indent parameter (default: compact, to preserve existing callers' behavior). Slice 2's exporter passes indent: 2.

File format notes (slice 2 ↔ #1660)

Slice 2's exported format is intentionally a subset of what #1660's styles: section will look like — same { vertices, edges } record-of-types shape, same lucide: icon refs. When the unified config lands, a slice-2 export can drop straight into #1660 under styles:.

Deliberately NOT in this PR

  • No /defaultStyling static route in app.ts — that's slice 3, folded into the unified config (Unified server configuration file #1660) per kmcginnes's direction.
  • No auto-fetch in AppStatusLoader.tsx — slice 3.
  • No example/defaultStyling.json or Docker-mount docs — slice 3.

Validation

  • pnpm run check:types — clean
  • pnpm run check:lint — 0 errors / 0 warnings (oxlint)
  • pnpm run check:format — clean (oxfmt)
  • pnpm test — all pass
  • pnpm coverage — all four thresholds met
  • Manually validated against a live Neptune backend. Confirmed: vertex labels/icons/colors apply on import; edge labels/colors apply on import; per-type Reset restores to the imported baseline; full Reset works both with and without an import; round-trip Export → Import preserves all styling including lucide: icon refs.

Related Issues

Check List

  • I confirm that my contribution is made under the terms of the Apache 2.0 license.
  • I have verified pnpm checks passes with no errors.
  • I have verified pnpm test passes with no failures.
  • I have covered new added functionality with unit tests if necessary.
  • I have updated documentation if necessary.

jkemmererupgrade and others added 6 commits May 22, 2026 14:10
Stores icon selections as symbolic lucide:<name> references rather than
data URIs, so config files remain human-readable and the picker can
highlight the current selection without reverse-engineering the blob.

Resolution happens at render time via two paths:
- React components (VertexIcon): useResolvedIconUrl hook backed by
  React Query (staleTime: Infinity) converts lucide:<name> to a base64
  SVG data URI on first use and caches the result.
- Cytoscape pipeline (renderNode): getLucideSvgString resolves directly
  from the lucide-react dynamic-import map, skipping any fetch round-trip.

Custom-uploaded icons (data: URIs and plain URLs) are unchanged -- they
pass through both resolvers untouched.

The new IconPicker component (searchable popover, 8-column grid, 50-icon
default window) is wired into NodeStyleDialog alongside the existing file
upload button so users can choose a Lucide icon or keep uploading their own.

Also fixes a pre-existing lint-staged misconfiguration where the root
oxlint --fix task matched vitest.config.ts, which oxlint then ignored
(matching its own ignorePatterns), causing exit code 1. The root
lint-staged config now mirrors the oxlint ignorePatterns by routing
*.config.* files to oxfmt only and restricting oxlint to packages/.

Pre-flight: pnpm checks, pnpm test (1738/1738), pnpm coverage all pass.
This is Slice 1 of the 3-slice split of aws#1589 per @kmcginnes review.
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Add three buttons to the General Settings page:
- Export: downloads current vertex and edge styling as graph-explorer-styling.json
- Import: loads a JSON file, applies it as the live styling baseline, and stores it in
  defaultStylingAtom so per-type Reset on the node style dialog restores to imported
  values rather than application defaults
- Reset All: reverts every vertex and edge to the imported baseline (or application
  defaults if no file has been imported this session)

Introduce defaultStyling.ts with a Zod schema (DefaultStylingSchema), parseDefaultStyling,
resolveDefaultStyling (converts lucide:<name> shorthand to iconUrl references established
by the Lucide icon picker in PR aws#1777), and userStylingToExportFormat. The file format
round-trips cleanly via lucide:<name> refs.

Add mergeDefaultsIntoUserStyling to userPreferences.ts so imported baselines fill gaps
for unstyled types without overwriting user customisations.

Update toJsonFileData with an optional indent param (defaults unchanged) so the exported
file is human-readable.

Add unit tests for the schema, parse/resolve pipeline, hooks, and reset behaviour.
Update docs/features/settings.md and docs/features/graph-view.md accordingly.

Slice 2 of the 3-slice split of aws#1589.
Stacks on aws#1777 (Lucide icon picker).
…rkers

useResolvedIconUrl is no longer used after VertexIcon switched to DynamicIcon
per maintainer feedback on aws#1777.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kmcginnes

Copy link
Copy Markdown
Collaborator

Thanks @jkemmererupgrade. Are you still good with me pushing up any changes needed to your branch rather than following the typical review/feedback/change loop?

@kmcginnes

kmcginnes commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

@kmcginnes kmcginnes modified the milestones: Release v3.1, Release v3.2 Jun 15, 2026
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