Skip to content
Open
6 changes: 6 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Graph Explorer Change Log

## Unreleased

- Add defaultStyling.json support for persistent per-type vertex and edge
styling (#1265, #112, #173, #573, #689)
- Add Lucide icon picker to node styling dialog

## Release 3.0.3

This patch release blocks cross-origin requests by default, improves performance for larger schemas, adds inferred edge connections in search and expansion, and adds a diagnostic logging setting.
Expand Down
2 changes: 2 additions & 0 deletions docs/references/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@ Technical reference documentation for Graph Explorer covering configuration, sec
- [Security](./security.md) - HTTPS connections, certificates, and permissions
- [Health Check](./health-check.md) - Proxy server health and readiness endpoint
- [Logging](./logging.md) - Log levels, output, and proxy server logging modules
- [Default Connection](./default-connection.md) - Configure a default connection via environment variables or JSON
- [Default Styling](./default-styling.md) - Configure default vertex and edge styling via a JSON file
165 changes: 165 additions & 0 deletions docs/references/default-styling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
# Default Styling Configuration

Graph Explorer supports an optional `defaultStyling.json` file that provides
default vertex and edge styling for all users. This is useful for:

- Non-persistent browser environments (e.g., AWS WorkSpaces Web) where IndexedDB
is cleared between sessions
- Pre-configuring a shared visual style for teams
- Providing a consistent starting point for new users

## How It Works

On startup, Graph Explorer fetches `defaultStyling.json` and merges its values
into the user's per-type styling preferences (stored in IndexedDB). Default
values fill in any properties the user hasn't explicitly set — existing user
overrides are preserved.

When no `defaultStyling.json` is mounted, behavior is identical to the default
Graph Explorer experience. When mounted, it populates the per-type styling that
users can then customize. Resetting a vertex or edge style in the UI will revert
to the `defaultStyling.json` values (or the hardcoded application defaults if no
entry exists for that type).

## Setup

### Docker

Mount the file into the container's configuration folder:

```bash
docker run \
-v /path/to/defaultStyling.json:/graph-explorer/packages/graph-explorer/defaultStyling.json \
public.ecr.aws/neptune/graph-explorer
```

### Custom Icons

To serve custom icon files (referenced by URL in the config), mount an icons
directory:

```bash
docker run \
-v /path/to/defaultStyling.json:/graph-explorer/packages/graph-explorer/defaultStyling.json \
-v /path/to/icons:/graph-explorer/packages/graph-explorer/custom-icons \
public.ecr.aws/neptune/graph-explorer
```

Icons in the `custom-icons` directory are served at `/custom-icons/<filename>`.

## JSON Schema

```json
{
"vertices": {
"<VertexTypeLabel>": {
"color": "#hex",
"icon": "lucide-icon-name",
"iconUrl": "url-or-base64",
"iconImageType": "image/svg+xml",
"shape": "ellipse",
"displayLabel": "Custom Label",
"displayNameAttribute": "name",
"longDisplayNameAttribute": "description",
"backgroundOpacity": 0.4,
"borderWidth": 0,
"borderColor": "#hex",
"borderStyle": "solid"
}
},
"edges": {
"<EdgeTypeLabel>": {
"displayLabel": "Custom Label",
"displayNameAttribute": "name",
"labelColor": "#hex",
"labelBackgroundOpacity": 0.7,
"labelBorderColor": "#hex",
"labelBorderStyle": "solid",
"labelBorderWidth": 0,
"lineColor": "#hex",
"lineThickness": 2,
"lineStyle": "solid",
"sourceArrowStyle": "none",
"targetArrowStyle": "triangle"
}
}
}
```

All properties are optional — only specify what you want to override. Type
labels must exactly match the vertex/edge type names in your graph database.

### Icons

There are three ways to set vertex icons:

- **Icon Picker (UI)** — In the Node Style dialog, click **Browse** to search
and select from the full Lucide icon library (~1,900 icons).
- **`icon`** — A [Lucide](https://lucide.dev/icons) icon name in kebab-case
(e.g., `"user"`, `"log-in"`, `"landmark"`). Resolved to an SVG at runtime. No
additional files needed.
- **`iconUrl`** — A URL or base64 data URI for a custom icon. Use this for
non-Lucide icons. If both `icon` and `iconUrl` are specified, `iconUrl` takes
precedence.

### Vertex Shapes

Available shapes: `ellipse`, `rectangle`, `diamond`, `triangle`, `pentagon`,
`hexagon`, `heptagon`, `octagon`, `star`, `barrel`, `vee`, `rhomboid`, `tag`,
`round-rectangle`, `round-triangle`, `round-diamond`, `round-pentagon`,
`round-hexagon`, `round-heptagon`, `round-octagon`, `round-tag`,
`cut-rectangle`, `concave-hexagon`.

### Line Styles

Available for edges and borders: `solid`, `dashed`, `dotted`.

### Arrow Styles

Available for `sourceArrowStyle` and `targetArrowStyle`: `triangle`,
`triangle-tee`, `circle-triangle`, `triangle-cross`, `triangle-backcurve`,
`tee`, `vee`, `square`, `circle`, `diamond`, `none`.

## Common Lucide Icons for Graph Use Cases

| Use Case | Icon Name |
| -------------------- | --------------------------------- |
| Person / User | `user` |
| Account / Bank | `landmark` |
| Email | `mail` |
| Phone | `phone` |
| Login / Auth | `log-in` |
| Device | `monitor`, `laptop`, `smartphone` |
| IP Address / Network | `globe`, `network` |
| Transaction | `arrow-left-right` |
| Location | `map-pin` |
| Organization | `building` |
| Alert | `shield-alert`, `triangle-alert` |
| Document | `file-text` |
| Calendar / Date | `calendar` |
| Lock / Security | `lock`, `shield` |
| Database | `database` |
| Server | `server` |
| Link / Relationship | `link` |

See the full list at [lucide.dev/icons](https://lucide.dev/icons).

## Import / Export / Reset

The Settings page provides styling management:

- **Export Styling** — exports the current per-type styling as a
`defaultStyling.json` file, for sharing or Docker-mounting as team defaults.
- **Import Styling** — imports a `defaultStyling.json` file. This is an
alternative to mounting the file in Docker.
- **Reset All Styling** — resets all styling to defaults. If a
`defaultStyling.json` is mounted, those values are restored; otherwise,
styling reverts to the application defaults.

Per-type reset is also available in the Node/Edge Style dialogs via the "Reset
to Default" button.

## Example

See [`example/defaultStyling.json`](../example/defaultStyling.json) for a
complete example with banking-oriented vertex and edge types.
86 changes: 86 additions & 0 deletions example/defaultStyling.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{
"vertices": {
"User": {
"color": "#1565C0",
"icon": "user",
"shape": "ellipse"
},
"Account": {
"color": "#2E7D32",
"icon": "landmark",
"shape": "ellipse"
},
"Login": {
"color": "#EF6C00",
"icon": "log-in",
"shape": "ellipse"
},
"EmailAddress": {
"color": "#C62828",
"icon": "mail",
"shape": "ellipse"
},
"PhoneNumber": {
"color": "#6A1B9A",
"icon": "phone",
"shape": "ellipse"
},
"Device": {
"color": "#00838F",
"icon": "monitor",
"shape": "rectangle"
},
"IPAddress": {
"color": "#4E342E",
"icon": "globe",
"shape": "diamond"
},
"Transaction": {
"color": "#1B5E20",
"icon": "arrow-left-right",
"shape": "ellipse"
},
"Location": {
"color": "#E65100",
"icon": "map-pin",
"shape": "ellipse"
},
"Organization": {
"color": "#283593",
"icon": "building",
"shape": "rectangle"
}
},
"edges": {
"OWNS": {
"lineColor": "#2E7D32",
"lineThickness": 2,
"lineStyle": "solid"
},
"TRANSFERRED_TO": {
"lineColor": "#1B5E20",
"lineThickness": 3,
"lineStyle": "solid"
},
"HAS_EMAIL": {
"lineColor": "#9E9E9E",
"lineThickness": 1,
"lineStyle": "dashed"
},
"HAS_PHONE": {
"lineColor": "#9E9E9E",
"lineThickness": 1,
"lineStyle": "dashed"
},
"LOGGED_IN_FROM": {
"lineColor": "#EF6C00",
"lineThickness": 2,
"lineStyle": "solid"
},
"LOCATED_AT": {
"lineColor": "#E65100",
"lineThickness": 1,
"lineStyle": "dotted"
}
}
}
8 changes: 8 additions & 0 deletions packages/graph-explorer-proxy-server/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ export function createApp({
"/defaultConnection",
express.static(path.join(configPath, "defaultConnection.json")),
);
app.use(
"/defaultStyling",
express.static(path.join(configPath, "defaultStyling.json")),
);
app.use(
"/custom-icons",
express.static(path.join(configPath, "custom-icons")),
);

// Host the Graph Explorer UI static files
app.use(staticFilesVirtualPath, express.static(staticFilesPath));
Expand Down
6 changes: 0 additions & 6 deletions packages/graph-explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,6 @@
"vite": "^8.0.9",
"vitest": "4.1.5"
},
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"oxfmt"
]
},
"engines": {
"node": ">=24.13.0"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,15 @@ const useInitCytoscape = ({
}, 100);
cy.on("pan", debouncedPan);

// eslint-disable-next-line react-hooks/set-state-in-effect -- intentional: tracking external Cytoscape instance
setCy(cy);

return () => {
(cy.elements() as any).removeAllListeners();
(cy as any).removeAllListeners();
cy.destroy();
cy.unmount();

setCy(undefined);
};
}
Expand Down
Loading