Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
182 commits
Select commit Hold shift + click to select a range
546ea7e
refactor(utilities): move sanitizeForAST into StaticUtilities
Mnikley Jul 15, 2026
e147aa3
feat(io): add Neo4j connector via HTTP transactional Cypher API
Mnikley Jul 15, 2026
86463fd
chore(scripts): fix ruff findings in package_latex_submission
Mnikley Jul 15, 2026
84f2f6a
fix(io): wire Neo4j popup buttons before Popup relocates the footer
Mnikley Jul 15, 2026
9b57fa5
feat(io): polish Neo4j connector UX, checklist metadata, auto-coloring
Mnikley Jul 15, 2026
0da6051
chore: sync package-lock version to 1.15.5
Mnikley Jul 15, 2026
e72e142
chore(release): 1.16.0 — Neo4j connector
Mnikley Jul 15, 2026
a60655f
fix(io): map Neo4j booleans to categorical strings so filters match
Mnikley Jul 15, 2026
97a8c7a
fix(io): normalize boolean D4Data values at the shared import boundary
Mnikley Jul 15, 2026
bab0586
chore(release): 1.16.1 — boolean property filtering fix
Mnikley Jul 15, 2026
c04583f
feat(neo4j): expand selection and join-query merge for active sessions
Mnikley Jul 15, 2026
db873ca
fix(ui): disambiguate same-named properties in the pie slice picker
Mnikley Jul 15, 2026
771c508
chore(release): 1.16.2 — pie picker property disambiguation
Mnikley Jul 15, 2026
4c5392d
feat(neo4j): add Stack Overflow demo prefill and legible edge palette
Mnikley Jul 16, 2026
9b87d3a
feat(neo4j): log executed Cypher queries in the status log
Mnikley Jul 16, 2026
c409a15
chore(release): 1.16.3 — Cypher query visibility in status log
Mnikley Jul 16, 2026
502e7ec
Merge branch 'main' into feat/neo4j-connector
Mnikley Jul 27, 2026
6d3f1cf
feat(ui): keyboard cheat sheet, Tools open by default, drop Details t…
Mnikley Jul 27, 2026
6a91eef
feat(filters): boolean property inference and visible mixed-type columns
Mnikley Jul 27, 2026
9f04f69
refactor(filters): drop boolean numeric override; min width for filte…
Mnikley Jul 27, 2026
5c5673b
feat(ui): the rail — consolidate header, toolbar, workspace bar and s…
Mnikley Jul 27, 2026
068cdbe
feat(ui): the inspector — one context-driven panel replaces four
Mnikley Jul 29, 2026
66d6536
feat(ui): the workbench — four non-destructive tabs over the stage
Mnikley Jul 29, 2026
fb35edd
fix(ui): workbench eyeball — minimap lift, drag skeleton, metrics layout
Mnikley Jul 29, 2026
01886c5
fix(metrics): repaint on return to a cached metric; ⤢ takes the full …
Mnikley Jul 29, 2026
02c7639
feat(filters): the expanded filter surface — columns, search, active-…
Mnikley Jul 29, 2026
4c394ea
fix(a11y): name the range slider thumbs; AA contrast on dark brand pills
Mnikley Jul 29, 2026
4a713c3
fix(filters): stop complete-cases AND from wiping a whole element type
Mnikley Jul 29, 2026
5cdbed4
feat(filters): show which filters actually constrain the graph under AND
Mnikley Jul 29, 2026
e7189ff
feat(ui): ⌘K over every control, scraped from the interface itself
Mnikley Jul 30, 2026
c8f75de
feat(ui): toast the newest message, keep the log as a disclosure
Mnikley Jul 30, 2026
140bb4e
feat(ui): global undo/redo over the workspace's view state
Mnikley Jul 30, 2026
8698625
feat(ui): split the inspector into Filters, Overlays and Selection
Mnikley Jul 30, 2026
c7dd92f
feat(ui): make every route out of the empty state a button
Mnikley Jul 30, 2026
d6af236
feat(heatmap): fade the graph for real, instead of recoloring it grey
Mnikley Jul 30, 2026
de50323
feat(filters): halve the panel — one-line numerics, node/edge segment…
Mnikley Jul 30, 2026
e9408ff
docs: record the inspector polish pass
Mnikley Jul 30, 2026
c2dfb59
fix(filters): fixed-width threshold boxes; clamp long labels
Jul 30, 2026
78c6ba9
feat(annotations): text notes — place, drag, edit, style, export
Jul 30, 2026
ae4a3eb
fix(inspector): grey the Density Heatmap card while the overlay is off
Jul 30, 2026
fc1fe16
refactor(ui): move the Note tool from the rail strip into Overlays
Jul 30, 2026
b861b55
refactor(filters): merge the node/edge segment into the section heade…
Aug 3, 2026
b078c6a
refactor(filters): drop the expand-over-the-stage surface, keep the s…
Aug 3, 2026
a7fa9b7
feat(overlays): fold the rail's ◐ menu into an inspector layer stack
Aug 3, 2026
2cc2ec7
feat(landing): warn and gate graph actions when WebGL2 is missing
Aug 4, 2026
071461d
refactor(groups): drop the unread per-filter group sets and the Props…
Aug 4, 2026
f44e085
refactor(groups): scope every group-list read to the layout it writes
Aug 4, 2026
31c4cf6
feat(groups): unbounded, named bubble groups with one group list
Aug 4, 2026
e9f5e5f
docs(groups): update the tour, changelog and architecture notes
Aug 4, 2026
464943e
fix(groups): repair two defects found in the live app
Aug 4, 2026
33a2f9f
fix(groups): keep the settings heading readable while the pane is dimmed
Aug 4, 2026
5b83c6b
refactor(groups): move the Groups list DOM into managers/group_list.js
Aug 4, 2026
ebda713
test(groups): cover the behaviours the audit found unprotected
Aug 4, 2026
258d6e7
feat(groups): keep drags responsive and rework the list from feedback
Aug 4, 2026
e0c8b36
fix(groups): repaint the filter chips on any style write, and show th…
Aug 4, 2026
54d6af9
fix(groups): make the settings switches work, and drop the pane heading
Aug 4, 2026
8b4bc38
fix(groups): round the bubble marching grid to whole pixels
Aug 4, 2026
642f38a
fix(groups): stop the painted hull overshooting across thin corridors
Aug 4, 2026
d0ec791
fix(overlays): grey a layer switch that has nothing to draw, and reco…
Aug 4, 2026
f37ee55
feat(inspector): flash the pill instead of switching context on its own
Aug 4, 2026
1e084a2
fix(filters): make the +/- selection control opaque while it is enlarged
Aug 4, 2026
5979c50
fix(cards): dim a disabled card's contents, not its heading
Aug 4, 2026
e432e93
refactor(rail): make Search look and sit like the rest of the rail
Aug 4, 2026
e6e0677
fix(a11y): give the app its own focus ring instead of Chrome's black one
Aug 4, 2026
31d0c10
fix(filters): stop the bool toggle stretching to full column width
Aug 4, 2026
57b1acb
docs(tour): resync the guided tour with the current UI
Aug 4, 2026
109920b
docs(tour): fix the rail step's phantom diamond and duplicate Search
Aug 4, 2026
ff9aa94
docs(tour): drop the Mac key equivalents
Aug 4, 2026
69ca638
fix(hover): stop hover highlighting through filtered-out edges
Aug 4, 2026
0cebe24
feat(ui): replace native title tooltips with a styled delegated layer
Aug 4, 2026
0e5c2cd
chore(release): 1.17.0 — the rail, the inspector and the workbench
Aug 4, 2026
482a03d
fix(rail): clamp menus to the bottom viewport edge
Aug 5, 2026
2b9ff70
fix(bubbles): condition the field ring so hulls paint smooth, not wobbly
Aug 5, 2026
4857331
feat(bubbles): layout-aware initial group settings, with a Re-tune ac…
Aug 5, 2026
e41f911
fix(security): escape imported text in the Data Editor table
Aug 5, 2026
3773493
fix(neo4j): skip the count preflight for write-shaped queries
Aug 5, 2026
a5ca06d
fix(ui): give the labeled-card wash a theme token
Aug 5, 2026
069d3d9
chore(deps): clear the audited CVE backlog
Aug 5, 2026
6ffee77
fix(history): record node drags and note changes for undo
Aug 5, 2026
2edfda8
fix(rail): confirm before opening a file over a loaded graph
Aug 5, 2026
2e57f65
fix(neo4j): drop an abandoned join instead of merging it anyway
Aug 5, 2026
df6470d
fix(filters): include boolean segments in reset and Add to query
Aug 5, 2026
1ccd792
fix(filters): apply a typed threshold on blur, and correct out-of-range
Aug 5, 2026
632a6f8
fix(assistant): confirm before clearing the conversation
Aug 5, 2026
9f8e9ed
chore: ignore release audit worksheets
Aug 5, 2026
0911bc2
fix(rail): tie a menu's lifetime to its anchor, and let keyboards rea…
Aug 5, 2026
c80b481
fix(groups): report a failing group action instead of dropping it
Aug 5, 2026
7a6ac50
fix(a11y): make popups real dialogs
Aug 5, 2026
8b13028
fix(neo4j): scope stitching to the new batch, and stop it sinking a f…
Aug 5, 2026
c4bb9f3
refactor(neo4j): share the preflight flow and the colour helper
Aug 5, 2026
b94a724
fix(neo4j): abort a dismissed request instead of letting it land
Aug 6, 2026
b73c532
refactor(neo4j): share the checklist popup scaffolding
Aug 6, 2026
4d6b82a
fix(import): refuse Excel columns that would write to a prototype
Aug 6, 2026
f78e22a
chore(deps): pin exceljs onto a patched uuid
Aug 6, 2026
4f60d52
test: cover the three untested paths this release rewrote
Aug 6, 2026
c8be204
perf(notes): skip the note reconcile on frames where nothing moved
Aug 6, 2026
ce0a281
fix(palette): admit that a capped element list may have more behind it
Aug 6, 2026
4f716bb
fix(palette): treat class-disabled controls as disabled
Aug 6, 2026
d53b7b9
fix(a11y): let a disabled control explain why it is disabled
Aug 6, 2026
8e860bd
fix(hotkeys): leave browser and OS chords alone
Aug 6, 2026
b102727
fix(filters): keep folds through a search, and say when nothing matches
Aug 6, 2026
d95bfc3
fix(groups): tell a partial group row what the click will do
Aug 6, 2026
42c02f7
test(filters): pin the locked-state dimming of the join toolbar
Aug 6, 2026
1400f2a
fix(notes): show the armed tool, and keep the style popover on screen
Aug 6, 2026
174f990
fix(history): stop undo announcing a workspace switch
Aug 6, 2026
dceba90
refactor: retire three duplicated definitions
Aug 6, 2026
ea7ac06
refactor: break up the three longest UI builders
Aug 6, 2026
6fed198
refactor(filters): split buildFilterUI, and cover it end to end
Aug 6, 2026
145472f
chore(lint): clear the 15 standing unused-binding warnings
Aug 6, 2026
c3011e6
fix(neo4j): stop the connector lying about three things
Aug 6, 2026
dc38de1
fix(notes): make Escape mean cancel, and say when a paste is trimmed
Aug 6, 2026
edf10ec
fix(palette): stop offering hidden elements, and restore the kbd chip
Aug 6, 2026
3984780
fix(ui): six small lies in the interface
Aug 6, 2026
d45bb7a
fix(a11y): keep the card hover bar readable in dark mode
Aug 6, 2026
17e7601
fix(history): stop recording changes that did not happen
Aug 6, 2026
cc17583
refactor: retire dead surface, name three magic numbers
Aug 6, 2026
09c70c9
chore(server): harden served documents, and say what the API does not…
Aug 6, 2026
0999efb
fix(rail): keep Escape inside an open menu
Aug 6, 2026
af6c35d
docs(changelog): record the 1.17.0 audit-fix pass
Aug 6, 2026
04190cb
chore(deps): lock the Python playwright at the npm version
Aug 6, 2026
b35c928
chore(deps): move the desktop shell to Electron 43
Aug 6, 2026
ac9c035
docs(contributing): say when the Electron runtime is downloaded
Aug 6, 2026
af85c33
fix(ui): stop the sliders and tooltips fighting over the pointer
Aug 6, 2026
775b229
fix(a11y): keep a disabled card's collapse bar clickable
Aug 6, 2026
ff2e1b3
fix(security): escape imported text in tooltips and scale pickers
Aug 7, 2026
3d983f1
fix(ui): lift toasts above the landing page and modal overlays
Aug 7, 2026
b90fa41
fix(neo4j): report post-close failures instead of writing to dead DOM
Aug 7, 2026
6764305
fix(data-editor): clear pending changes on reset
Aug 7, 2026
96162e8
fix(notes): record and announce a note emptied out of existence
Aug 7, 2026
01121f6
fix(ui): confirm before the tour or STRING replaces a loaded graph
Aug 7, 2026
1f6a2b9
fix(metrics): treat an unscorable view as a result, not a missing one
Aug 7, 2026
d01f598
fix(io): parse a file before destroying the loaded graph
Aug 7, 2026
99235dc
fix(a11y): restore focus to the anchor when a rail menu closes
Aug 7, 2026
d7eea2b
fix(a11y): use theme tokens for the contrast failures in dark mode
Aug 7, 2026
5f3d723
fix(ui): give the rail's Hover toggle the same on-state as its siblings
Aug 7, 2026
a0b4161
chore(deps): override undici to 7.29.0
Aug 7, 2026
1028df5
perf(neo4j): stop the count preflight re-running the whole query
Aug 7, 2026
558c910
refactor(graph): share one overlay-canvas prep between the two layers
Aug 7, 2026
44f02da
fix(a11y): keep focus on the group control that triggered a rebuild
Aug 7, 2026
a06e068
fix(a11y): trap Tab inside modal popups
Aug 7, 2026
e7a3b6a
fix(neo4j): let the user cancel an expand
Aug 7, 2026
3bb4b61
test(groups): cover the per-group settings pane
Aug 7, 2026
b4a60a4
perf(bubbles): paint cached outlines under the camera transform
Aug 7, 2026
82e9eab
perf(history): hash the snapshot signature and skip no-op clones
Aug 7, 2026
94b6026
fix(tour): theme the step previews instead of pinning them light
Aug 7, 2026
12de12d
refactor(io): move the Excel schema and template out of io.js
Aug 7, 2026
69b383b
refactor(graph): share one frame coalescer across the overlay layers
Aug 7, 2026
c41fa10
refactor(io): lift the Excel cell decoders out of parseExcelToJson
Aug 7, 2026
92a532f
refactor(style): lift the style div's DOM primitives to module scope
Aug 7, 2026
c0deb56
fix(security): validate the Host header against the bind address
Aug 7, 2026
786fc76
chore(ci): harden the release workflow
Aug 7, 2026
7004197
chore(security): close the small standing exposures
Aug 7, 2026
9e610b1
fix(security): keep executed Cypher out of the assistant context
Aug 7, 2026
7079b74
fix(security): confirm plaintext credentials, and let users forget them
Aug 7, 2026
3f69827
chore(deps): cap pandas below 3
Aug 7, 2026
b941efb
fix(a11y): say the states the UI only showed, and open the resize han…
Aug 7, 2026
caceb4e
perf(neo4j): stop expand and stitch doing work the query already rule…
Aug 7, 2026
8581005
test: cover the untested seams the audit named
Aug 7, 2026
98e8137
fix(groups): evict the outgoing workspace's bubble groups on a switch
Aug 7, 2026
bcf246e
fix(groups): price avoidance per group instead of refusing it by grap…
Aug 7, 2026
e2c7d02
chore: delete the dead code the audit named
Aug 7, 2026
8c07e66
fix(style): give the rail one radius and the type scale whole pixels
Aug 7, 2026
5d217d7
fix(ux): make the confirm dialogs say what they do, and stop errors b…
Aug 7, 2026
b077b03
fix(assistant): stop a cancelled or empty turn leaving debris behind
Aug 7, 2026
484f85d
fix(neo4j): say what actually went wrong, and keep the submit shut un…
Aug 7, 2026
b569636
fix(ux): stop the panel controls acting where the user cannot see it
Aug 7, 2026
7c4004d
fix(ux): give notes and the tour a way out that says what happened
Aug 7, 2026
6434b26
fix(ux): answer the clicks and keystrokes that used to do nothing
Aug 7, 2026
7ee6252
perf(render): cull off-screen groups and stop float radii thrashing t…
Aug 7, 2026
ac038aa
perf(metrics): compose the tooltip metric line at hover, not into the…
Aug 7, 2026
be0a9ba
refactor(dedup): one accelerator parser, one placement home, one grou…
Aug 7, 2026
6342943
refactor(graph): split the overlay cache keys out, and fix the module…
Aug 7, 2026
026958b
refactor(graph): one visible-member collector, one bubble-label resolver
Aug 7, 2026
c25828f
refactor(style): name the stacking order, and token the brand borders
Aug 7, 2026
43007bf
docs(comments): drop the citations that resolve to nothing, and the h…
Aug 7, 2026
899ff88
refactor(cleanup): one collapse setter, a pure seeder, and a generic …
Aug 7, 2026
624cb9b
refactor(seams): announce the data source, declare the state, share t…
Aug 7, 2026
7d5c3e6
refactor(popup): move the workspace dialog out, and cover the heatmap…
Aug 7, 2026
7fb68dc
refactor(neo4j): one lifecycle for both fetch dialogs
Aug 7, 2026
66ea41a
refactor(notes): measure the note box once, paint it twice
Aug 7, 2026
ea0168f
refactor(groups): rebuild the Auto-detect popover on RailMenu
Aug 7, 2026
734a1d9
docs(changelog): record the second audit sweep's execution pass
Aug 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
- 'v*'
workflow_dispatch:

permissions:
contents: read

jobs:
build-windows:
runs-on: windows-latest
Expand All @@ -19,7 +22,7 @@ jobs:
node-version: '22'

- name: Install dependencies
run: npm install
run: npm ci

- name: Run dist build (Windows)
run: npm run dist-windows
Expand All @@ -46,7 +49,7 @@ jobs:
node-version: '22'

- name: Install dependencies
run: npm install
run: npm ci

- name: Run dist build (Linux)
run: npm run dist-linux
Expand Down Expand Up @@ -75,7 +78,7 @@ jobs:
node-version: '22'

- name: Install dependencies
run: npm install
run: npm ci

- name: Run dist build (macOS)
run: npm run dist-mac
Expand All @@ -93,6 +96,8 @@ jobs:
release:
needs: [build-windows, build-linux, build-macos]
runs-on: ubuntu-latest
permissions:
contents: write # creates the GitHub release
steps:
- name: Checkout code (for git log)
uses: actions/checkout@v4
Expand Down Expand Up @@ -150,12 +155,17 @@ jobs:
found { print }
' CHANGELOG.md)
# Write to multiline output
echo "notes<<EOF" >> $GITHUB_OUTPUT
# Random delimiter: a CHANGELOG line reading exactly "EOF" would
# otherwise close the block early and inject further step outputs.
DELIM="notes-$(openssl rand -hex 16)"
echo "notes<<$DELIM" >> $GITHUB_OUTPUT
echo "$NOTES" >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
echo "$DELIM" >> $GITHUB_OUTPUT

- name: Create Release
uses: softprops/action-gh-release@v1
# Pinned to a commit: a mutable tag can be repointed at any time,
# and this action holds a token that can write releases.
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
tag_name: ${{ steps.tag.outputs.tag }}
body: ${{ steps.changelog.outputs.notes }}
Expand All @@ -176,9 +186,11 @@ jobs:
needs: [release, deploy-demo]
if: always()
runs-on: ubuntu-latest
permissions:
actions: write # deletes the intermediate build artifacts
steps:
- name: Delete intermediate artifacts
uses: geekyeggo/delete-artifact@v5
uses: geekyeggo/delete-artifact@f275313e70c08f6120db482d7a6b98377786765b # v5
with:
name: |
windows-dist
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ src/gll.bundle.js.map
# Perf benchmark artifacts (regenerate via npm run perf:fixture / npm run perf)
scripts/fixtures/

# Release audit worksheets (/audit-sweep output, working docs — not release artifacts)
AUDIT-*.md

# Compiled Java class files
*.class

Expand Down
6 changes: 4 additions & 2 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ To group by data instead of by id, use `groupOneProps` — e.g.
(handy with §6 categorical values).

Useful `bubbleSetStyle.<group>` fields: `fill`, `fillOpacity`, `stroke`,
`strokeOpacity`, `virtualEdges` (boolean), `label` (boolean), `labelText`,
`strokeOpacity`, `padding`, `corridor`, `avoidance`, `label` (boolean), `labelText`,
`labelFill`, `labelFontSize`, `labelBackground`, `labelBackgroundFill`,
`labelBackgroundRadius`, `labelPlacement`.

Expand Down Expand Up @@ -488,7 +488,9 @@ an `active` flag plus slider thresholds or selected categories.
> `LOWER THAN <a> OR GREATER THAN <b>` (always two-sided — there is **no**
> standalone `LOWER THAN`), `IN [value1, value2]`, or the unary `IS MISSING`
> (true when the property is absent/empty or belongs to the other element type;
> emitted automatically by the filter panel's non-strict AND join) — with
> emitted automatically by the filter panel's non-strict AND join) or
> `IS FOREIGN` (true only when the property belongs to the other element type;
> emitted by the AND join's "complete cases only" mode) — with
> clauses combined by `AND` / `OR` / `NOT` and grouped in parentheses. There are
> no `<`, `>`, or `=` operators.

Expand Down
110 changes: 90 additions & 20 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Sigma — which presents a stable facade over the `graphology` graph held in
`src/graph/graph_model.js`. Managers talk to the adapter and the model, never to
Sigma directly.

### Graph layer (`src/graph/`, 27 files)
### Graph layer (`src/graph/`)

The rendering and graph-operation core. Key modules:

Expand All @@ -33,46 +33,113 @@ The rendering and graph-operation core. Key modules:
- `core.js` — `GraphCoreManager`: render/draw cycles, event locks, behaviour wiring
- `interactions.js` — drag, zoom, lasso, click, hover handlers
- `style.js` — per-element style resolution with defaults, per-layout persistence
- `layout.js` / `layout_algorithms.js` — workspace management; headless layouts
- `layout.js` / `layout_algorithms.js` / `workspace_dialog.js` — workspace
management, the "Create New Workspace" dialog, and headless layouts
(force via graphology forceAtlas2; circular/grid geometric; radial/concentric/mds
via `@antv/layout` v2)
- `filter.js` — range-slider + dropdown filtering
- `selection.js` — selection state with undo/redo memory
- `bubble_sets.js` / `bubble_layer.js` / `bubble_geometry.js` — bubble-set grouping
drawn on an owned canvas layer beneath the nodes
drawn on an owned canvas layer beneath the nodes. A workspace holds ANY number
of groups: the list is `Object.keys(layout.bubbleSetStyle)`, not a constant, so
every caller reads it through `traverseBubbleSets()` — which describes the
SELECTED workspace, and code touching a different layout (`io.parseLayouts`,
`layout.createDefaultLayout`) must key off that layout's own map instead.
Membership has two sources unioned by `getEffectiveGroupMembers`:
`${group}Props` (filters, resolved live) and `${group}ManualMembers` (node IDs,
a snapshot)
- `bubble_tuning.js` / `bubble_smoothing.js` — the layout-aware initial group
settings behind ✨ Re-tune, and the Catmull-Rom ring painter/resampler both the
canvas layer and the SVG export draw through
- `annotation_layer.js` / `annotation_geometry.js` — text notes: a DOM overlay
over the stage (place/drag/edit/style popover) plus the node-safe box metrics
the layer, the PNG export and the SVG export all measure with
- `heatmap_layer.js` / `heatmap_geometry.js` — node-density heatmap overlay (off by
default; toggled from the workspace toolbar)
default; one row of the inspector's Overlays layer stack, which owns both its
switch and its parameters — see `UIManager.OVERLAYS`)
- `edge_programs.js` / `edge_flow_programs.js` / `edge_flow_glsl.js` /
`flow_animator.js` — custom WebGL edge programs and the animated source→target
flow overlay (dash/pulse/comet/chevron)
- `overlay_frame.js` — the one rAF/signature/teardown coalescer the three
owned-canvas overlays (bubbles, heatmap, notes) render through
- `overlay_keys.js` — the "has the cached fit gone stale?" keys those layers
compare (member-id key, position checksum, style key)
- `shortest_path.js` — shortest-path selection between two picked nodes
- `label_renderers.js`, `pie_slices.js`, `shape_textures.js`, `minimap.js`,
`visible_graph.js`, `lasso_geometry.js`, `communities.js`, `export_svg.js`,
`webgl_support.js`
`webgl_support.js`, `dpr_watch.js`

### Functional managers (`src/managers/`, 7 files + `assistant/`)
### Functional managers (`src/managers/`, plus `assistant/`)

Business logic and UI:

- `io.js` — `IOManager`: Excel/JSON loading, export (JSON / PNG / SVG), data
preprocessing, Excel template generation
- `ui.js` — loading overlays, UI enable/disable, notifications
- `query.js` — query DSL with an AST (AND/OR/NOT, BETWEEN, IN, IS MISSING, comparisons)
- `ui_components.js` — filter UI (dropdown checklists, invertible range sliders), tooltips
- `ui_style_div.js` — the styling panel (node/edge styles, badges, edge flow, density heatmap)
- `metrics.js` — `NetworkMetrics`: degree/betweenness/closeness/eigenvector centrality, PageRank
preprocessing; the Excel column schema lives in `excel_schema.js` and the
downloadable workbook in `excel_template.js`
- `ui.js` — loading overlays, UI enable/disable, notifications, presentation mode,
and the inspector's overlay layer stack (`OVERLAYS`: one table row per thing
drawn over the graph, each layer answering `visible`/`setVisible`)
- `rail.js` — the 52 px top rail and its dropdown menus (app, workspace, layout,
select, export)
- `inspector.js` — the single right-hand panel's context router
(Filters / Overlays / Selection). `CONTEXTS` is the whole contract: the tab
roles, roving tabindex and arrow-key nav are generic over it, and panel and
pill ids are derived from the context name
- `workbench.js` — the bottom surface over the stage; four non-destructive tabs
(Data, Query, Metrics, Assistant) with a remembered height each
- `filter_search.js` — the property search over the inspector's filter list; the
box itself is built into `#filterContainer` by `ui.buildFilterUI`, so one
delegated listener here survives every rebuild
- `command_palette.js` — `⌘K` / `Ctrl+K`: one search over every control, node and
edge. The index is scraped from the live DOM on each open, so it cannot drift
from the UI; rows print the control's breadcrumb and accelerator
- `history.js` — global undo/redo (`Ctrl+Z` / `Ctrl+Y`). Snapshots the current
workspace's whole view state and restores it through `lm.changeLayout()`, so a
feature that stores something new on the layout is undoable for free
- `query.js` — query DSL with an AST (AND/OR/NOT, BETWEEN, IN, IS MISSING, IS FOREIGN,
comparisons)
- `ui_components.js` — filter UI (dropdown checklists, invertible range sliders),
the per-row group chip, tooltips
- `group_menu.js` — the one group checklist, opened by both assign sites (a filter
row assigns a property, the Selection panel assigns nodes); built on `RailMenu`
- `community_menu.js` — the 🧩 Auto-detect configurator (Louvain weighting,
resolution, how many groups); also a `RailMenu`, so Escape, `aria-expanded`,
close-on-scroll and focus restore come for free
- `group_list.js` — the Groups list under Overlays › Groups (rows, the ⋯ menu, the
+/- selection buttons). DOM only: it is handed the bubble-set MANAGER rather
than reaching for it through the cache, and every state change routes back
through it. `bubble_sets` keeps `renderGroupList`/`syncGroupRows` delegators so
callers still have one entry point
- `ui_style_div.js` — builds every config card (node/edge styles, badges, edge flow,
bubble sets, density heatmap, select/act/arrange); `ui.js` `CARD_MOUNTS` then
re-parents each card to its single home in the rail or the inspector. The Groups
card is a list (painted by `bubble_sets.renderGroupList`) over ONE settings pane
rebuilt for the selected row by `buildGroupStylePanel` — a pane per group would
be N × ~20 rows of DOM for a surface showing one group at a time
- `metrics.js` — `NetworkMetrics`: degree/betweenness/closeness/eigenvector centrality, PageRank.
Computed lazily — only while its workbench tab is visible (`setWorkbenchVisible`)
- `api_client.js` — client for the standalone ingest service
- `assistant/` — the natural-language Graph Assistant (intent parsing, query
generation, settings, budget UI)
generation, settings, budget UI); rendered as a workbench tab, not a dock

### Utilities (`src/utilities/`, 12 files)
### Utilities (`src/utilities/`)

- `static.js` — validation, colour math, deep-merge helpers
- `popup.js` / `popover_position.js` — modal and popover positioning
- `popup.js` / `popover_position.js` / `checklist_popup.js` / `fetch_popup.js` —
modal, popover positioning (anchor clamping plus the dropdown flip-up maths),
checklist dialogs, and the shared lifecycle of a "fetch into the graph" dialog
(abort on dismiss, spinner, inline-or-toast errors, submit locked across the
gates) that both Neo4j popups run on
- `ui_tooltip.js` — the delegated tooltip layer: strips native `title`s and
renders them itself, and owns `splitShortcut`, the one parser for the trailing
"(F)" accelerator the command palette also reads
- `data_editor.js` — spreadsheet-like data editor (`DataTable`), incl. Excel export
- `demo_loader.js` — STRING DB protein-interaction demo data
- `neo4j_loader.js` — Neo4j connector (HTTP transactional Cypher API, no driver dependency)
- `neo4j_session.js` — Neo4j session extensions: expand selected nodes, merge additional queries
- `tour.js` — guided tour with a sample dataset
- `color_scale_picker.js` / `numeric_scale_picker.js` / `pie_chart_picker.js` — styling pickers
- `selection_hud.js`, `theme.js`, `export_scale.js`
- `excel_merge.js`, `theme.js`, `export_scale.js`

### Key files

Expand All @@ -99,7 +166,10 @@ mapping bidirectionally between properties and node/edge IDs.
Maps on `cache` for O(1) lookups.

**Workspaces** — each layout independently stores node positions, styles,
filters, bubble groups, and queries.
filters, bubble groups, and queries. A workspace's groups live in three keyed
places — `bubbleSetStyle[group]`, `${group}Props`, `${group}ManualMembers` — and
deleting a group must clear all three, or `io.savedLayoutGroupKeys` infers the
group back from the orphan on the next load.

## Build & Run

Expand All @@ -126,9 +196,9 @@ src/
├── graph_lens_lite.html # SPA page
├── style.css # all CSS
├── lib/ # vendored libs (sigma, graphology, exceljs, marked, purify)
├── graph/ # rendering + graph operations (27 files)
├── managers/ # business-logic managers (7 files + assistant/)
├── utilities/ # helpers (12 files)
├── graph/ # rendering + graph operations
├── managers/ # business-logic managers + assistant/
├── utilities/ # helpers
└── package/ # Electron main process + build scripts
server/ # standalone ingest service + live viewer
templates/ # Excel input templates
Expand Down
Loading
Loading