Skip to content

Add styling import / export / reset UI#3

Closed
jkemmererupgrade wants to merge 109 commits into
mainfrom
feature/styling-import-export
Closed

Add styling import / export / reset UI#3
jkemmererupgrade wants to merge 109 commits into
mainfrom
feature/styling-import-export

Conversation

@jkemmererupgrade

Copy link
Copy Markdown
Owner

Description

Slice 2 of the 3-slice split of aws#1589 per @kmcginnes's review on that PR. This is the Styling Import / Export / Reset UI. Stacks on slice 1 (aws#1777) because it relies on the lucide:<name> 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": "<name>" field that gets converted to "iconUrl": "lucide:<name>" 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 ↔ aws#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:<name> 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 aws/graph-explorer#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 — 1787 / 1787 pass
  • pnpm coverage — all four thresholds met (statements 65.19%, branches 45.47%, functions 58.81%, lines 72.59%); branches floor auto-bumped from 45 → 45 (genuine improvement from new tests).
  • Manually validated against a live Neptune backend (k8s-port-forwarded). Confirmed: vertex labels/icons/colors apply on import; edge labels/colors apply on import (after correcting the test file's edge names to match the deployed schema); 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:<name> 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 (docs/features/settings.md, docs/features/graph-view.md).

kmcginnes and others added 30 commits March 10, 2026 15:02
…#1573)

Move permissions to the workflow level with contents: read for all three
workflows. This follows the principle of least privilege and ensures any
future jobs inherit the restricted token by default.

- unit.yml: Add permissions (was missing entirely)
- build_docker.yml: Move from job level to workflow level
- test_build_docker.yml: Move from job level to workflow level
* Update all dependencies

* Remove overrides that are no longer necessary
* Move ECS Fargate docs

* Move Sagemaker docs

* Move troubleshooting to guides

* Move connections to individual guides

* Table of contents and update links
* Move minimum requirements to refs

* Move HTTPS to refs

* Move health check to refs

* Move logging to refs

* Move permissions to refs

* Move default connections to refs

* Move security to refs

* Add summary

* Fix broken links

* Update title

* Combine security, https, and permissions to one file
* Update github skill

* Disable blank issues

* Update issue templates
… config directory (aws#1598)

* fix: use CONFIGURATION_FOLDER_PATH in docker-entrypoint.sh for custom config

* clean up entrypoint grep path

---------

Co-authored-by: Neel Shah <neeljs@amazon.com>
- Bump @aws-sdk/credential-providers from ^3.1005.0 to ^3.1015.0
- Replace fast-xml-parser override with flatted override for eslint chain
* Remove leftover corepack cache from Docker image

* Add Trivy vulnerability scan to Docker test build
schemaSyncQuery now accepts an options object with a hasConnection flag
that gates the enabled option. When no active connection is configured,
both schema discovery and edge connection queries stay idle, preventing
unnecessary network calls.
…e' (aws#1611)

When no connections are configured, views now show a 'No Connection' empty
state with a link to the Connections page instead of 'No Schema Available'.
The Connections page shows an empty state with add/import buttons instead
of auto-opening the create dialog. Dialog state is now owned by
AvailableConnections using Radix DialogTrigger.
* Add tests for process-environment.sh

* Use proper posix compliant printf

* Verify custom config path by checking file existence at both paths
* Extract createApp from node-server.ts with comprehensive tests

* Extract createServer for testable HTTP/HTTPS decision

* Extract resolveServerConfig with buildBaseUrl and tests
- Move cert generation and validation from docker-entrypoint.sh to setup-ssl.sh
- Accept CERT_DIR and HOST as environment variables
- Use absolute paths with CERT_DIR instead of cd + relative paths
- Use portable sed pattern matching instead of hardcoded line numbers
- Preserve existing behavior including known bugs (duplicate rootCA.crt check)
- Add 7 tests documenting current behavior including bug test case
* Add RequestValidationError for Zod-based request validation

Introduce a custom RequestValidationError that wraps ZodError, replacing ad-hoc error creation with status code assignment. The error handler detects this error type and returns a 400 response with the prettified Zod error message. Also handle 400 responses in the client display error utility.

* Clean up nits from review: un-export BooleanStringSchema, add JSDoc, add invalid URL test
* Improve error details with richer diagnostic information

* Add more extractErrorMessage tests with negative cases

* Simplify conditional data field in createErrorDetails
* Add security policy and security audit workflow

* Address review feedback for security audit workflow

* Remove pnpm audit step from security audit workflow

* Remove SLA and public issue instruction
* Remove ExplorerInjector component

The ExplorerInjector was originally added to inject the explorer instance
into the query client meta field and clear the cache on connection change.
Both responsibilities are already handled elsewhere:

- The store is injected at query client creation time in createQueryClient()
- Cache clearing happens via queryClient.removeQueries() in useResetState(),
  which is called at every connection switch point

Resolves aws#1646

* Add tests for createQueryClient and useResetState
* Improve error details and add test coverage

- Fix ErrorDetails.message type to allow undefined
- Hide error message field in dialog when undefined
- Consolidate extractMessageFromData into extractErrorMessage
- Add comment explaining serializeCause name handling
- Add tests for NetworkError and fetchDatabaseRequest
- Simplify decodeErrorSafely to return raw text for non-JSON responses
  instead of wrapping in { message } since extractErrorMessage handles
  strings directly

* Handle connection to proxy errors

* Tighten types and add edge-case tests

* Add security policy and security audit workflow (aws#1648)

* Add security policy and security audit workflow

* Address review feedback for security audit workflow

* Remove pnpm audit step from security audit workflow

* Remove SLA and public issue instruction

* Remove ExplorerInjector component (aws#1649)

* Remove ExplorerInjector component

The ExplorerInjector was originally added to inject the explorer instance
into the query client meta field and clear the cache on connection change.
Both responsibilities are already handled elsewhere:

- The store is injected at query client creation time in createQueryClient()
- Cache clearing happens via queryClient.removeQueries() in useResetState(),
  which is called at every connection switch point

Resolves aws#1646

* Add tests for createQueryClient and useResetState

* Extend loopback check to include IPv6 and 0.0.0.0
Migrate from Vite 7 to Vite 8, which replaces esbuild + Rollup with
Rolldown + Oxc for bundling, transforms, and minification.

Dependency changes:
- vite 7.3.1 → 8.0.8
- @vitejs/plugin-react 5.1.4 → 6.0.1
- @tailwindcss/vite 4.2.1 → 4.2.2
- babel-plugin-react-compiler 19.1.0-rc.3 → 1.0.0
- vitest / @vitest/coverage-v8 4.0.18 → 4.1.4
- Add @rolldown/plugin-babel 0.2.2
- Remove vite-tsconfig-paths (now built-in)

Config changes:
- Replace vite-tsconfig-paths plugin with resolve.tsconfigPaths: true
- Move React Compiler to separate @rolldown/plugin-babel plugin with
  reactCompilerPreset, since @vitejs/plugin-react v6 removed built-in
  Babel support
- Remove unnecessary /// <reference types="vitest" /> directive

Resolves aws#1647
jkemmererupgrade and others added 4 commits May 28, 2026 15:13
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.
@jkemmererupgrade jkemmererupgrade force-pushed the feature/styling-import-export branch from c9fa43c to 9ed29c2 Compare May 28, 2026 21:21
kmcginnes and others added 9 commits May 28, 2026 16:30
…#1790)

* Remove broken lint-staged config from graph-explorer sub-package

The sub-package lint-staged referenced eslint which is no longer
installed. The root package.json lint-staged already runs oxlint
and oxfmt on all staged files, making the sub-package config
redundant.

* Add CLAUDE.md that references AGENTS.md for project conventions

* Update lockfile after removing lint-staged from sub-package
* Fix 3 moderate security vulnerabilities from pnpm audit

Update dependencies to resolve brace-expansion DoS, ws memory
disclosure, and qs DoS vulnerabilities:
- @tanstack/eslint-plugin-query 5.100.6 → 5.100.14 (pulls fixed
  @typescript-eslint/utils with minimatch/brace-expansion >=5.0.6)
- pnpm update ws (resolves happy-dom's ws to >=8.20.1)
- pnpm update qs (resolves superagent's qs to >=6.15.2)
- Update brace-expansion override from <5.0.5 to <5.0.6

* Update Amazon Linux releasever to 2023.11.20260526

Bumps the yum releasever pin to pick up latest package versions
including libcap 2.73-1.amzn2023.0.7.
The trailing slash in `.claude/` only matches directories, not symlinks.
Removing it allows git to ignore both.
…ws#1800)

* fix: use label().groupCount() for neighbor counts on Neptune 1.3.x

The batched neighbor count query nested group().by(label).by(count())
inside an outer by(), which triggers an InternalFailureException on
Neptune engine 1.3.x. Replacing the inner traversal with
label().groupCount() produces the same g:Map of label to count and
works on both 1.3.x and 1.4.x engines, so no parser changes are needed.

Fixes aws#1798

* fix: use groupCount().by(label) per review feedback

The maintainer's team verified groupCount().by(label) on Neptune
v1.2.1.0, v1.3.2.1, and v1.4.7.0. It produces the same g:Map of label
to count and is consistent with the existing groupCount().by(label)
usage in the schema label templates.
…1801)

Documents how we use the `internal` and `help wanted` labels plus
standard footer callouts to signal issue audience.
* feat(icons): add built-in Lucide icon library for node styling

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.

* address PR review feedback

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>

* Remove dead code, consolidate Lucide icon utilities, fix edge cases

- Remove unused useResolvedIconUrl hook and resolveIconUrl/lucideIconToDataUri
- Rename lucideIconUrl.ts to lucideIcons.ts and export IconName type and
  allIconNamesSorted so consumers share a single source of truth
- Make isLucideIconRef a proper type guard, eliminating non-null assertion
- Fix renderNode to resolve lucide: refs regardless of iconImageType
- Fix IconPicker truncation hint to show whenever results are capped
- Add tests for new exports, error paths, and edge cases

* Revert unrelated lint-staged config change in root package.json

* Fix lint and type errors in lucideIcons utilities

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Kris McGinnes <kmcginnes@me.com>
Both vertex and edge schema templates now use g.V().limit(1) as a dummy
anchor instead of g.E() / g.V().union().fold(). The .by() modulators run
independent global sub-traversals so the anchor value is irrelevant, but
this change ensures Neptune's DFE engine handles the full query natively
on all tested versions (1.2.1.0, 1.3.5.0, 1.4.7.0).

Closes aws#1803
@kmcginnes

Copy link
Copy Markdown

@jkemmererupgrade It looks like I'm not allowed to change the target of this PR now that the original target is merged. Could you update it for me?

kmcginnes added 9 commits June 5, 2026 09:48
…ets (aws#1794)

* Add PROXY_SERVER_ALLOWED_DB_ORIGINS to restrict proxy forwarding targets

Introduces an optional allowlist for database origins the proxy server
will forward to, mitigating SSRF risk. Also refactors error handling
with an HttpError base class and disables HTTP redirects on outbound
requests.

* Document PROXY_SERVER_ALLOWED_DB_ORIGINS in configuration and security references

* Note that direct connections bypass the allowed DB origins check

* Improve security and configuration docs for proxy server
Migrate to pnpm 11 by moving overrides from package.json to
pnpm-workspace.yaml, removing the devEngines.packageManager field
which now conflicts with the packageManager field, and replacing
the deprecated onlyBuiltDependencies/ignoredBuiltDependencies/
strictDepBuilds settings with the new allowBuilds map.
* Switch schema sync summary API from detailed to basic mode

Basic mode returns all fields Graph Explorer uses (nodeLabels,
edgeLabels, numNodes, numEdges) without the unused nodeStructures
and edgeStructures. Also makes the proxy forward query params
as-is instead of hardcoding mode=detailed.

Removes broken lint-staged config from graph-explorer sub-package
(referenced removed eslint; root config already handles linting).

Closes aws#1789

* Remove request-forgery suppression comment

The SSRF concern is properly addressed by assertAllowedDbOrigin and the
origin check in resolveEndpointUrl.

* Break taint chain for CodeQL SSRF detection

Use a known route path + URLSearchParams(req.query) instead of passing
raw req.url to resolveEndpointUrl. This breaks the CodeQL taint chain
while preserving the same behavior of forwarding query params.

* Hardcode mode=basic in proxy and restore type-level enforcement

Revert to hardcoding the summary mode in the proxy routes instead of
forwarding raw query params. This eliminates the need for
buildEndpointWithQuery and avoids the CodeQL SSRF taint chain entirely.

Restore the template literal type constraint on resolveEndpointUrl to
reject leading-slash endpoints at compile time.
…ws#1813)

* Set border-opacity on per-type node styles to fix invisible borders (aws#1812)

The base node style sets borderOpacity: 0, but the per-type style
overrides from useGraphStyles never set border-opacity. Cytoscape
cascades the base value, keeping borders invisible regardless of
user settings.

* Add border-width assertion back to the zero-width test case
* Add paging to the icon picker

Replace the icon picker's hard 64-icon cap and "type to search" hint
with paging through the full icon list. Adds a minimal footer (Page X of
Y plus prev/next chevrons) modeled on the query results list, 64 icons
per page. Page position persists while the style dialog stays open and
resets on search or when the dialog reopens.

* Use Tooltip component for icon picker icons

Replace the native title attribute on each icon button with the Button
tooltip prop, giving a styled tooltip and an aria-label accessible name.
Tests identify icon buttons by aria-pressed and read names from
aria-label, and wrap renders in TooltipProvider as the app does.

* Lower function coverage threshold to match CI

The autoUpdate ratchet bumped the function threshold to 60 from a local
coverage measurement, but CI measures 58.47% functions and fails. Revert
the function floor to 58 (its pre-paging value); statements, branches,
and lines stay at the ratcheted values, which CI still meets.
@jkemmererupgrade

Copy link
Copy Markdown
Owner Author

Morning @kmcginnes! Sorry I was out on vacation last week, merging master now and updating the target.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jkemmererupgrade jkemmererupgrade changed the base branch from feature/lucide-icon-picker to main June 15, 2026 15:36
@jkemmererupgrade

Copy link
Copy Markdown
Owner Author

@kmcginnes had to create a new PR: aws#1824

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.

4 participants