V3 fable auto#22
Merged
Merged
Conversation
Replace networkx/scipy/python-louvain with python-igraph (same C core as R igraph — all v2 algorithms port 1:1, see SPEC). Package management via uv: deps in pyproject.toml + uv.lock, requirements.txt deleted. Remove stale algorithms/ scaffold dirs (SPEC now uses flat service modules). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…1 complete) Dev: docker-compose with uv + node images, hot reload both sides, VITE_PROXY_TARGET for in-network proxying. Prod: multi-stage build, nginx serves Vite dist + proxies /api to uvicorn on one image (v2 r-base Dockerfile replaced; v2 preserved via v2-legacy tag). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports config/server_variables.R + global_variables.R into app/config.py (RColorBrewer Set3/Set1 palettes inlined as hex). Endpoint serves the v2 handler_initializeGlobals payload plus node palette, floor defaults, topology metric and no-edge-layout lists. static_variables.R was mutable Shiny state, ui_variables.R a footer year — both obsolete. All four R config files deleted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports the parseUploadedNetwork() chain from functions/input.R: subset legit columns, trim, dedup (channel-aware), scale weights into 0.1..1 via mapper(), build Node_Layer keys. Validation mirrors isNetworkFormatValid() (missing mandatory columns, non-numeric weight, empty channel) as HTTP 400; MAX_LAYERS/MAX_EDGES enforced at the API boundary. 12 pytest cases incl. real aspirin_3channels.tsv fixture. input.R deletion deferred to Phase 7 (still holds JSON import, session export, attribute uploads). Added pandas-stubs; mypy target 3.12 for numpy stub syntax. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports functions/igraph/layout.R + general.R graph construction: - services/graph.py: channel filter, perLayer/allLayers/nodesPerLayers scopes, simplify (sum parallel weights, keep loops) - services/layouts.py: registry of all 11 v2 UI layouts as Graph.layout_* calls, per-request RNG seed (v2 set.seed(123)), returns 2D [y,z] - no-edge layouts (Circle/Grid/Random) place isolated layer nodes as extra vertices (simpler equivalent of v2 filterPseudoNetwork) 24 pytest cases. layout.R deleted; general.R kept as spec through Phase 6. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports functions/igraph/cluster.R. Clustering is an optional step of POST /api/layout (not a separate endpoint): detect communities (Louvain/Walktrap/Fast Greedy/Label Propagation via Graph.community_*), lay super-nodes out with the global algorithm repelled from origin, lay each community's members locally (real intra edges + tiny all-pairs edges so disconnected members spread), translate into place. Response gains a clusters map. 8 new pytest cases; cluster.R deleted. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports functions/igraph/topology.R: Degree (raw Graph.degree, not normalized centrality), Clustering Coefficient (weighted local transitivity, isolates=0), Betweenness (edge-direction toggle + weights). Values mapped per subgraph into [0.5, 2.5] via mapper() (constant → 1); raw values returned for the View Data table. 7 pytest cases. topology.R + general.R deleted — functions/igraph/ fully ported. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- POST /api/session/import: ports parseUploadedJSON + isJSONValid
(defaults for scene/layers/nodes/edges, channel drop, edge dedup,
scramble flag). Loads real Arena3DwebApp_aspirin.json / export JSONs.
- POST /api/session/export: thin JSON download (stateless — frontend
owns the state).
- POST /api/external + GET /api/external/{token}: session stored under
a random token in tmp/ with 24h TTL sweep + path-traversal guard;
resolves back through the same normalizer (SPEC §5).
- VR (functions/vr.R) DROPPED, not ported — depended on external
bib.fleming.gr hosting + A-Frame, out of scope (see MIGRATION.md).
11 pytest cases. Deleted init.R, general.R, reset.R, render.R,
js_handling.R, vr.R. input.R kept: attribute-upload functions still
to port to a future /api/attributes endpoint.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Foundation singletons: - bus/index.ts: typed pub/sub, unsubscribe handle (replaces rshiny bridge) - store/index.ts: single AppState source of truth - commands/base.ts: Command + CommandHistory (undo/redo, emits history:changed) - api/client.ts: hand-written typed fetch wrappers mirroring backend Pydantic models (no codegen dependency) — network/layout/topology/ session/external 5 Vitest tests; tsc + eslint clean (skipLibCheck for third-party stubs). Verified live: config/network/layout return 200, OpenAPI exposes all 9 paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Migrate Scene/Layer/Node/Edge from www/js/classes/ to typed frontend/src/three/ on npm three r170. Key finding: vendored www/js/three/three.js was byte-identical to stock Three.js r117 (diff = only a missing trailing newline). SPEC's "manually patched copy" claim is wrong — no core patches exist, so no src/three/ subclasses were needed. - constants.ts: static geometry + 280-color palette (verbatim from v2) - runtime.ts: typed ctx singleton replacing v2 ambient globals (registries, screen bounds, edge tunables, color-priority flags). nodeGroups/layerGroups were new Map() but only bracket-accessed in v2 -> typed as plain records. - Scene/Layer/Node/Edge.ts: faithful ports; only API change is THREE.Math -> THREE.MathUtils. - three.test.ts: 16 Vitest tests across all four classes. Deferred (ponytail-marked): Scene.rotate() DOM slider + Shiny glue and Layer.getColor() picker DOM read -> Phase 11 canvas_controls. Delete www/js/classes/ + three.js. Keep matrix4.js/drag_controls.js as living spec until Phase 11. tsc + eslint + prettier clean; 21/21 vitest pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implement the 8 Command classes in src/commands/scene.ts, each capturing before/after state on the Phase 9 Three.js object model so CommandHistory can undo/redo: - ChangeNodeColorCommand / ChangeNodeSizeCommand - ChangeEdgeColorCommand (captures colors + edgeFileColorPriority) - MoveLayerCommand (position/rotation/scale; redraws inter-layer edges) - ApplyLayoutCommand (positions + optional cluster IDs/colors, one step) - ApplyTopologyCommand (node scales) - ChangeThemeCommand (store-only via injected getter/setter) - LoadNetworkCommand (build closure + ctx registry snapshot for undo) Commands are thin: they apply/reverse already-decided values. API fetch and position/scale math is the Phase 11 actions' job, which will construct these commands with the results. Supporting changes: - runtime.ts: add ctx.edgeObjects registry + snapshotRegistries / restoreRegistries helpers (RegistrySnapshot). - bus: add layer:moved event. 9 Vitest tests (execute/undo/redo per command). tsc + eslint clean; 30/30 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port the portable, unit-testable slice of the v2 object_actions: src/actions/layout.ts — executeLayout coordinate normalization plus applyLayout / applyTopology, which fetch from the API and dispatch the Phase 10 ApplyLayoutCommand / ApplyTopologyCommand (one undo step each). Confirmed against backend: /api/layout returns raw igraph [y,z] coords (no layer-width normalization), so the frontend still performs the v2 mapping into [-minWidth/2, minWidth/2] * layer scale. Topology scales are already mapped server-side and applied verbatim. Re-scope the rest of Phase 11: the remaining 9 action files are coupled to the renderer, camera, animate() loop, raycaster, DragControls, CSS2D labels, and the UI panels — all built in Phases 12-13. They move to those phases (documented in PLAN.md) rather than being stubbed now, and www/js/object_actions/ deletion moves with them. ponytail: allLayers scope only; perLayer/local layout refinements deferred to the Phase 13 scope UI. 5 Vitest tests (normalize + applyLayout + applyTopology). tsc + eslint clean; 35/35 tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stand up the render spine so the app draws its first pixels. Verified
live with playwright-cli: /api/config loads, the WebGL canvas mounts,
and the tilted coordinate axes render.
- src/actions/screen.ts: port of screen.js — renderer, camera
(orthographic), window bounds, raycaster, FPS-limited animate() loop.
Shiny sync calls dropped. (screen.js was deferred out of Phase 11 for
exactly this dependency.)
- src/main.ts: port of on_page_load.js — config fetch -> renderer/
camera/scene setup -> mount canvas into #app -> animate. Exposes
window.__arena = { ctx, history } so Playwright can read 3D scene
state via page.evaluate (WebGL is opaque to the a11y tree).
- src/event_listeners.ts: window resize + Ctrl+Z / Ctrl+Shift+Z /
Ctrl+Y undo/redo wired to CommandHistory.
- src/utils.ts: port of general.js (pure helpers), 6 Vitest tests.
- runtime.ts: add ctx.renderer/camera/fps + screen bounds (persist
across network reloads; not reset by resetContext).
Deleted www/js/general.js (fully ported + tested).
Deferred: the canvas mouse/keyboard scene controls (clickDown/Drag/Up,
sceneZoom, keyPressed, right-click) land with canvas_controls (still in
the Phase 11 list). Documented in PLAN.md.
Updated PLAN.md Phase 13 to drive/verify DOM panels with playwright-cli
(@playwright/cli, installed) against the window.__arena hook.
tsc + eslint clean; 41/41 vitest pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…artial) buildNetwork consumes backend-parsed NetworkData: fresh Scene + ctx registries, layers spread on x, nodes scrambled per layer, edges grouped per src---trg pair with channel colors. loadNetwork wraps it in LoadNetworkCommand so an upload is one undo step. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port of www/js/object_actions/node.js pure parts: raycaster hover, double-click/search/select-all selection synced to the store, repaintNode (cluster branch folded into Node.getColor), label-flag priorities using Layer.isVisible instead of DOM checkboxes, shape/color-priority setters. scrambleNodes moves here from network.ts. ctx gains lastHoveredNodeIndex, selectedNodeColorFlag and the two node-label flags. DOM-bound pieces (search bar, sliders, lasso, node description div, attribute upload) stay with canvas_controls.ts / Phase 13 UI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 12 partial) Port of www/js/object_actions/edge.js pure parts: renderInterLayerEdges now runs every animate() tick (remove while dragging/paused/invisible, v2 locked-flag redraw pair), channel color/visibility, unselectAllEdges, and the edge-setting setters (direction, arrow sizes, width-by-weight, opacities, color priorities, curvatures). redrawIntra/InterLayerEdges move here from commands/scene.ts private helpers. ctx gains the four inter-layer render flags. Channel UI lists/picker stay with Phase 13; edge attributes upload with POST /api/attributes; edge build already lives in network.ts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…12 partial) Port of www/js/object_actions/layer.js pure parts: initialSpreadLayers moves here from network.ts, raycaster hover with red highlight + repaint, double-click/selectLayer/select-all selection synced to the store, repaintLayers with default/picker color priority, per-layer visibility and node-label toggles that recompute node label flags, plus the coords/opacity/wireframe/color-priority setters. ctx gains lastHoveredLayerIndex, hoveredLayerPaintedFlag, renderLayerLabelsFlag. Checkbox group + color-picker DOM stay with Phase 13; DragControls and the held-key/slider rotate/move/scale intervals with canvas_controls.ts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port of www/js/object_actions/themes.js: THEMES presets (light/dark/gray from the v2 buttons), applyTheme sets renderer clear color, ctx.edgeDefaultColor/labelColor, reassigns channel colors from the config palette and repaints layers picker-priority with the theme floor color. registerThemeListener() subscribes to theme:changed in main.ts, so ChangeThemeCommand execute/undo now performs the concrete recolour. Supporting: ctx.labelColor (v2 globalLabelColor), repaintLayers gains an optional pickerColor override, assignChannelColorsFromPalette lands in edge.ts. Theme buttons DOM + channel edit list stay with Phase 13; label recolour with labels.ts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port of www/js/object_actions/labels.js keeping v2's plain absolutely-positioned divs in #labelDiv (no CSS2DRenderer dep; inline position styling until the Phase 13 stylesheet). createLabels runs on network build; flag-gated renderLayerLabels/renderNodeLabels register as animate hooks via a new registerAnimateHook in screen.ts, which avoids a screen->labels->node->screen import cycle. showLayer/NodeLabels modes, label resize and setLabelColor ported; themes.ts now recolors labels on theme change and decideNodeLabelFlags raises the node render flag as v2 did. ctx gains renderNodeLabelsFlag + the two layer-label flags. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Port of the canvas half of www/js/event_listeners.js plus the held-key and lasso helpers it pulled from node.js/layer.js: wheel zoom, z/x/c axis keys + arrow-key pan (modern event.key), clickDown/Drag/Up with left-drag pan, middle-drag orbit, held-key node-translate/layer-rotate, shift-lasso rectangle select (dim to 0.5, select on mouse-up), and dblClick with v2's node -> layer -> unselect-all priority. registerCanvasControls() wires the listeners onto the mounted canvas from main.ts (tabIndex for keydown, scroll/autoscroll prevention, mouseleave button release). Shiny syncs and 100ms debounces dropped. Right-click node menu stays with right_click_menu.ts; DragControls layer dragging and the nav-button/slider table with Phase 13. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…artial) Port of www/js/object_actions/right_click_menu.js plus the context-menu builder from event_listeners.js: selectNeighbors, selectMultiLayerPath (v2 starting/current-layer exclusions), recursive selectDownstreamPath over inter-layer edges, and the executeCommand tail (render flags, label flags, store sync). The <select> menu is placed over the clicked node in #labelDiv; Link opens the node URL. Wired to the canvas contextmenu event and removed on clickUp in canvas_controls, as v2 did. Loader spinner + description panel content stay with Phase 13 UI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…x4.js Hand-port of v2's tweaked three.js DragControls copy onto npm three math (the matrix4.js shim goes away). v2 behavior kept: drag engages only while the left button is held over a hovered layer plane, label render flags raised while dragging, camera-facing drag plane with parent-space offset. On release it now raises the inter-layer edge render flag and emits layer:moved (v2 routed this through Shiny syncs). The planes list is read live from ctx so a single registration survives network reloads (v2 recreated DragControls per load). Registered from main.ts. Both v2 living-spec files deleted; MIGRATION.md rows ticked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ject_actions) screen.js, labels.js, themes.js, right_click_menu.js, event_listeners.js and on_page_load.js are fully covered by the ported TypeScript actions and main.ts; MIGRATION.md rows ticked. Kept as living spec for their unported remainders: layout.js (predefined/star/cube layouts), network.js (importNetwork session JSON), node.js/edge.js/layer.js/canvas_controls.js (Phase 13 DOM), config/, rshiny_handlers.js/rshiny_update.js (map to Phase 13 panels). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
buildFromSession consumes the backend-normalized SessionData (now typed in api/client.ts): scene position/scale/rotation + renderer clear color, full layer transforms (initial spread only when the backend generate_coordinates flag says the JSON carried none), nodes with positions/scale/color/url/descr (scramble per flag within min layer width), edges with per-row file colors and opacity as the weight, and the v2 setJSONExtras flags (label color, direction, width-by-weight, edgeFileColorPriority). loadSession wraps it in LoadNetworkCommand as one undo step. createEdgeObjects gains the v2 decideEdgeColors rule: a row's own color wins over the channel palette. The store receives a NetworkData equivalent so later layout/topology calls work on imported sessions too. network.js is now fully ported and deleted; MIGRATION.md ticked. Session export + File-panel wiring land with Phase 13. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e 12 partial) Port of v2 layout.js applyPredefinedLayout: scene tilt + layer reset (planes re-face the camera via its quaternion), parallel/zigZag spreads, starLike petals (each layer rotated its share of 360 degrees and pushed outward by half its width + 100), and the cube arrangement (6 layers per cube side, extra cubes offset along x). Direct layer transforms as in v2 (not undoable); raises the inter-edge + layer-label render flags in place of the v2 Shiny syncs. layout.js stays as living spec for the perLayer/local normalization refinements only (Phase 13 scope UI). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
collectSession assembles the export dict from live ctx state — scene pan/scale/rotation + renderer clear color, layer transforms, nodes, one edge row per channel with decideColor(j, forExport=true), and the setJSONExtras flags (label color, direction, edgeOpacityByWeight) — as v2 did through rshiny_update.js. exportSession POSTs it to /api/session/export and triggers a blob download; api.exportSession returns the Blob. Round-trip tested against buildFromSession. File-panel upload/download buttons land with Phase 13. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Action-panel drawers (File/Layouts/Scene/.../Data) could only be dismissed by navigating back to Main View through the navbar tabs. Add a small chevron handle docked to the drawer's left seam: '>' collapses the open drawer to the canvas, '<' reopens the last one that was open. Derives the active pane from the shown.bs.tab event's own data-bs-target rather than querying '.tab-pane.show': Bootstrap fires that event as soon as the (unanimated) nav button activates, before the pane's own fade transition adds its 'show' class, so a DOM query at that instant could still match the pane being deactivated. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
getRandomArbitrary drew from Math.random(), so every Load Example or upload scattered nodes to a different layout. Back it with a seeded mulberry32 PRNG and re-seed at the start of scrambleNodes with a fixed seed (123, mirroring the backend's random.seed(123)), so the same network always produces the same layout. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
After a network upload, Load Example, or session import succeeds, switch to the empty Main View pane so the drawer closes and the 3D scene is revealed without a manual tab change. The panelDrawerToggle picks up the change through its existing shown.bs.tab listener and shows the closed state. On error the drawer stays open so the message is visible. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Buttons attach top-right on first network load and dispatch ChangeThemeCommand, so theme switches are undoable. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
applyTheme set layer colors via repaintLayers(theme.floor) but never updated the #floor_color input, which is the source of truth on the picker priority path. Hover-exit repaint (repaintLayers() / Layer.getColor()) read the stale input and reverted layers to the dark default. Restore the v2 behaviour of writing the theme floor into #floor_color. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Taste skill UI ux update
Full-codebase review: 3 high, 7 medium, 6 low findings across backend session/external/clustering/topology and frontend edge/session/canvas-controls code. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Checkbox tracker for REPORT_CODE_REVIEW.md items plus unreadable select-option font color fix (U1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
main.ts now reads the ?session=<token> query param on load, resolves
it through GET /api/external/{token}, and loads the returned session.
resolveExternal typed as SessionData.
Closes H1 in PLAN.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reject sessions whose node.layer is not a known layer, or whose edge src/trg is not a known node id, with a 400 instead of letting the frontend crash on undefined.addNode / nodeObjects[-1]. Covers the third-party /api/external payload path. Adds two unit tests. Closes H2 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Match every child with userData.tag === channel instead of assuming a line/arrow interleave. Arrows are skipped for zero-opacity channels, so the old children[j+1] lookup hid the wrong sibling. Adds a regression test with a missing-arrow sibling channel. Closes H3 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Record the warning before popping channels (the post-pop guard was always false, so it never fired), thread warnings through SessionImportResponse, and show them in the file panel status line. Closes M1 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Duplicate names collapse the frontend layerGroups map, parenting the earlier layer's nodes onto the wrong plane. Fail with a 400 instead. Closes M2 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
buildFromSession derived source_node/target_node by chopping the layer suffix off the id, which mangles names that contain '_<layer>' and produced garbage when nodeGroups missed. Use a nodeId -> node map instead; backend referential validation guarantees the lookup hits. Closes M3 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The slope-based form collapsed a community to the origin whenever its super-node had x == 0 (common with Circle/Grid layouts) — the opposite of repelling it. Scale the vector directly; identical to the old form for x != 0. Closes M4 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wrap the per-file getmtime/remove in try/except OSError so a file removed by a concurrent request between listdir and stat no longer 500s /api/external. Closes M5 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One edge is a valid 2-node graph; the < 2 guard (with its incorrect 'cannot form a graph' comment) silently dropped those layers from scaling. Skip only truly empty scopes. Closes M6 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
importedColors shared the same array reference as colors, so a future single-array mutation would silently corrupt the file-color-priority baseline and undo. Clone it. Closes M7 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hover also dims a node to 0.5, so a node hovered at mouse-up outside the lasso rectangle was selected. Track covered nodes explicitly. Closes L1 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Guard the global undo/redo handler so keystrokes inside input, textarea, or contentEditable elements edit the text instead of undoing scene commands. Closes L2 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ctrl+Z with the canvas focused armed axis-transform mode; a following drag moved nodes/layers unintentionally. Skip axis arming on modified keydowns. Closes L3 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The module-local currentTheme shadowed store.currentTheme, which was never written. Route the ChangeThemeCommand getter/setter through the store so there is one source of truth. Closes L4 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
An edge channel missing from ctx.channelColors produced new THREE.Color(undefined) -> silent white. Fall back to the edge default color. Closes L5 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reading it at import time froze the value; env changes (redeploy, tests) were ignored. Read it inside the handler. Closes L6 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The native option popup rendered with the OS default light background while inheriting light --arena-text, leaving layout/clustering/topology select options light-on-light. Set an opaque dark background on .form-select option/optgroup. Closes U1 in PLAN.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix Plan — Code Review Findings
Source:
REPORT_CODE_REVIEW.md(commit 5f3a04a). One item = one commit. Check off when merged.High
frontend/src/main.ts, parsenew URLSearchParams(location.search).get('session'); if present, callapi.resolveExternal(token)andloadSession()after setup. E2E test: POST a session to/api/external, open returned URL, assert network loaded.backend/app/services/session.py _validate: reject node.layer ∉ layer names and edge src/trg ∉ node ids (HTTP 400). Unit tests for both.setChannelVisibilityarrow lookup — infrontend/src/actions/edge.ts, replace positionalchildren[j + 1]with lookup byuserData.tag === channel+ ArrowHelper type; toggle all matches, drop the fragile interleave assumption.Medium
session.py _handle_channels: compute warning before popping channels; return warnings throughSessionImportResponseand show in frontend file panel.session.py _validate: error on duplicatelayers[].name.source_nodeby slicing —frontend/src/actions/network.ts buildFromSession: resolve source/target node + layer from the session nodes list, notslice(0, -len-1)string surgery.backend/app/services/clustering.py _super_node_coords: replace slope hack with direct vector scaling(x * F, y * F)._sweeprace —backend/app/routers/external.py: wrap per-file stat/remove intry/except OSError: continue.backend/app/services/topology.py: verify v2 intent for thelen(layer_edges) < 2skip; either compute for 1 edge or return a client-visible warning.Edge.importedColors—frontend/src/three/Edge.ts:this.importedColors = [...this.colors].Low
canvas_controls.ts: track lasso-hit nodes in a Set instead of the opacity===0.5 sentinel (hover pollution).event_listeners.ts handleUndoRedo: return early whenevent.targetis input/textarea/contentEditable.canvas_controls.ts keyPressed: ignore z/x/c whenctrlKey || metaKey.store(or dropAppState.currentTheme); remove module-local duplicate inthemes.ts.Edge.decideColor:ctx.channelColors[...] ?? ctx.edgeDefaultColor.ARENA_PUBLIC_URLread per request —external.py: read env inside handler (or document the import-time constraint).UI
<select class="form-select">dropdowns (frontend/src/ui/layouts.ts) render light text on light background. Add explicitcolor/background-colorforselect.form-selectand itsoptions infrontend/src/style.cssso options are readable in all themes.