Feat/web v2 scaffold#11
Merged
Merged
Conversation
added 30 commits
May 22, 2026 15:15
The Dash-based web interface has been superseded by a new V2 app built on React + D3 + Canvas (in web/) with a FastAPI backend (in server/). The Dash port translated tkinter dialogs verbatim and never delivered a web-native UX. - Delete src/ontoloviz/web.py (1320 LOC) - Drop the [web] optional-dependency group (dash, dash-bootstrap-components, pandas) - Remove the ontoloviz-web console script - Refresh uv.lock (22 transitive packages removed) - Update README quickstart to point at the new V2 layout
Two-package scaffold for the V2 browser-based ontology visualizer. Frontend (web/): - Vite + React 18 + TypeScript (strict) + Tailwind - D3 (d3-hierarchy, d3-scale, d3-shape) for layout math; Canvas 2D for rendering (WebGL only if profiling later demands it) - Zustand for state, papaparse + SheetJS for file parsing - Vitest + ESLint + Prettier wired up - HealthIndicator polls /api/health via the Vite dev proxy Backend (server/): - FastAPI + uvicorn, uv-managed, separate pyproject.toml - Routers: /api/health (live), /api/obo (stub), /api/models (stub) - pytest + ruff configured; 3 smoke tests pass Architectural seam: propagation runs in the browser (TypeScript), not on the backend, so the future standalone interactive HTML export works offline. The backend handles data ingestion (OBO fetch, future external model adapters) and persistence only. Repo plumbing: - Top-level Makefile with make install / make dev / make test that wires both halves together (Vite on :5173, FastAPI on :8000) - web/README.md and server/README.md document each half independently The tkinter app (src/ontoloviz/) is untouched. core.py stays as the reference implementation for upcoming TS propagation ports.
- Add .idea/ to the repo-root .gitignore so JetBrains project files stop showing up in git status. - Pick up the prettier reformat the user/linter applied to web/src/App.tsx and web/tailwind.config.ts. No behavioral change.
Step 2 of the V2 rebuild: ingest the same TSV/XLSX formats the tkinter app supports, in TypeScript, with parity-tested behavior against the shipped templates. Data model (src/lib/ontology/types.ts): - Immutable Node, Subtree, Ontology types mirroring the Leaf/Branch shape from src/ontoloviz/core.py. - Warnings collected on the Ontology, never thrown. Parser (src/lib/ontology/parse.ts): - Three formats with auto-detection from the header row: * parent-based (ID / Parent columns) * separator-based MeSH (Tree ID column, '.' separator) * ATC (positional, variable-width step sizes per level) - Pipe-separated multi-id rows are expanded into individual nodes. - Missing ancestors are backfilled as synthetic nodes so every chain reaches its root, matching check_atc_parent / check_mesh_parent in the Python reference. - Pure: no I/O, no globals. Tests (tests/ontology/parse.test.ts): - 21 cases covering both shipped templates (templates/atc_template.tsv, templates/mesh_template.tsv) plus the parent-based template literal inherited from the deleted Dash port. - Covers level derivation, parent linkage, multi-id expansion, duplicate-id warnings, CRLF, UTF-8 BOM, and empty input. Repo housekeeping: - Anchor /lib/ and /lib64/ in .gitignore so the Python venv patterns stop swallowing web/src/lib/.
Parity tests against the real example datasets (templates/mesh_example_pubmed_mapped.tsv, templates/atc_example_covid_drugs_experimental.tsv) uncovered a bug where the MeSH and ATC parsers flagged a real row as duplicate when a synthetic placeholder for the same id had already been inserted by an earlier descendant's backfill pass. Example: D007239's tree id is "C01". Earlier rows reference "C01.150...", which causes backfillAncestors to create a synthetic "C01" node. When D007239's actual row arrives, the parser saw the existing node and emitted a "duplicate id" warning, dropping the real count (24636) on the floor. Fix: only flag duplicates when an existing *non-synthetic* node is present; otherwise the real row supersedes the placeholder. (The parse.test.ts diff is a pure prettier reformat that came with the change — no test logic was modified.)
Step 3 of the V2 rebuild: ports the count-propagation half of the tk app's propagation model to TS, with a parity contract against the Python reference. Engine (web/src/lib/ontology/propagate.ts): - Pure function propagateCounts(ontology, settings) covering the off / level / all modes. Returns a new Ontology — inputs are never mutated. - Deterministic bottom-up traversal (sorted by level, descending) so ancestor counts truly reflect every descendant. The legacy core.py MeSH path iterates in dict-insertion order and only propagates one level per pass; the V2 port fixes this intentionally. Unit tests (web/tests/ontology/propagate.test.ts): - 9 cases on a synthetic 6-node parent-based tree covering every mode, the level-threshold matrix, and the no-mutation invariant. Parity harness (tests/parity/generate_fixtures.py): - Loads templates/atc_example_covid_drugs_experimental.tsv and templates/mesh_example_pubmed_mapped.tsv through src/ontoloviz/core.py. - Runs the corrected (bottom-up) propagation on each tree across a matrix of (mode, level, enabled) combinations. - Dumps 10 JSON fixtures under web/tests/fixtures/parity/. Parity tests (web/tests/ontology/parity.test.ts): - Loads each fixture, runs the TS pipeline (parseTsv → propagateCounts) on the source TSV, and asserts every node's count matches the Python-derived expectation. Plumbing: - New `make parity-fixtures` target regenerates the JSON fixtures. - web/README.md gains a Parity section explaining the workflow and a roadmap checklist marking steps 1–2 (parsing, count propagation) complete.
- propagateColors(ontology, settings) covers off/specific/global/phenotype modes; returns a new Ontology, never mutates input - buildColorScale ports core.py's calculate_color_scale_for_node (factor selection + multi-stop linear RGB interpolation, Plotly n_colors parity) - phenotype mode walks bottom-up to color outermost nodes only; the legacy dict-insertion-order traversal in core.py degenerates to "color everything" when ancestors come before descendants — same family of order-dependency as the count-propagation fix - empty TSV color cells resolve to defaultColor at propagation time so every node ends up renderable - 20 unit tests on a synthetic dotted tree + RGB helpers, 11 parity fixtures covering all four modes plus level gates and the disabled no-op path on both MeSH and ATC example datasets - tests/parity/generate_fixtures.py extended with a build_color_scale / propagate_colors port; emits to web/tests/fixtures/parity-color/ - web/README.md roadmap marks step 3 done; parity section documents the bottom-up divergence in both algorithms
…orts, and OBO backend Web: - D3 partition + Canvas sunburst renderer with click-to-zoom and breadcrumb trail - Zustand store driving live count/color propagation across all surfaces - Settings panel with mode pickers, level thresholds, and editable scale stops - Virtualized summary grid with bidirectional hover linking and case-insensitive search - High-DPI PNG, SVG, and self-contained HTML exports with native browser tooltips Server: - OBO parser handling [Term] stanzas, multi-parent placement, obsolete filtering, and cycle promotion to synthetic roots - POST /api/obo/parse and GET /api/obo/fetch (httpx proxy with timeout and size cap) - Typed model-adapter contract (ModelProvider, PredictRequest/Response) reserved for future external providers Docs rewritten to describe the production app instead of a phased roadmap.
Shows a modal overlay during file upload with stage label, byte/node detail, and a determinate progress bar. Stages: read file, parse TSV, propagate counts & colors, render. requestAnimationFrame yields between stages so the overlay paints between blocking CPU work.
Replaces .eslintrc.cjs with eslint.config.js (flat config) wiring @typescript-eslint, react, react-hooks, and prettier. Adds @eslint/js and globals devDeps required by flat config. Fixes the source issues surfaced once linting actually ran: - SettingsPanel.tsx: import ReactNode explicitly instead of relying on the React global - Sunburst.tsx: import MouseEvent from react instead of React.MouseEvent - parse.ts: replace literal U+FEFF in the BOM-stripping regex with \uFEFF escape
… theming - Switch to cohesive dark editorial theme via CSS-variable tokens consumed by Tailwind through `rgb(var(...) / <alpha-value>)`, enabling per-attribute theme swaps and proper alpha modifiers. - Add dark/light theme toggle (ThemeToggle + lib/theme) with localStorage persistence and pre-paint bootstrap in index.html to avoid FOUC. - Promote the header to a real toolbar: subtree picker, filename, health, theme, export menu, settings toggle, reset, load-new. - Replace always-on settings sidebar with an animated slide-in drawer scoped to <main>, dismissable via scrim or close button. - Replace always-on summary grid with a collapsible panel exposing inline-editable label/count/color cells; edits flow through a new store action `updateNode` that produces a fresh immutable ontology so propagation re-runs automatically. - Replace inline three-button ExportBar with a header dropdown ExportMenu (PNG 2x / SVG / standalone HTML). - Add real empty state with hero copy and feature cards. - Theme native chrome: range thumbs, scrollbars, color inputs, selects, and `color-scheme` follow the active theme. - Rename accent-button foreground token to `text-on-accent` so the same class produces dark-on-orange in dark mode and white-on-orange in light mode.
- Cap buildColorScale's interpolated array at 1M entries by widening the factor when needed, so a typo like count=1e13 no longer hangs the tab. Real ATC/MeSH maxima stay under the cap and parity holds. - Wrap inline data-table edits in the existing LoadingOverlay so the re-propagation pass on large trees is visible instead of looking frozen. App passes an onEdit handler that yields two RAFs around the store mutation. - Default SummaryGrid to the active subtree only and add an "all subtrees" toggle. Header count reflects the scoped view.
- Remove the "Reset" and "Load new…" buttons from the loaded-state header. Uploads happen from the landing page; clearing happens via the brand mark. - Make the OntoloViz logo+title clickable when an ontology is loaded. Clicking opens a centered ConfirmDialog (alertdialog) that warns the current data and inline edits will be discarded. Backdrop click and Escape both cancel; Reset is the focused accent action. - Mirror LoadingOverlay's single-child flex-center layout so the dialog centers reliably without an absolute-positioned backdrop sibling fighting the flex container.
- Replace marketing EmptyState (gradient headline, accent pill, feature grid) with a discreet graph_lens_lite-style landing: compact ring mark, short subtitle, primary "Open File" CTA, three sibling cards, faint footer. Subtle network-pattern overlay + soft accent radials, theme-aware via existing CSS vars. - Add OBO Foundry picker modal with seven curated presets (HPO, MONDO, DOID, GO, ChEBI, Uberon, CL) plus a free-form .obo URL input. - Add fetchObo() helper that calls /api/obo/fetch and converts the wire JSON to the frontend's Map-based Ontology shape. - Wire "Try an Example" through the existing upload pipeline via a CustomEvent so the loading overlay + parser path stays single-sourced. - Bundle atc_template, mesh_template, and one ATC COVID example under /templates for the download + example cards. - Drop the header's redundant Choose-TSV button and the glowing accent brand mark in favor of a small square + name.
- Landing background now stretches the full main area - ATC and MeSH templates are separate first-class cards - COVID-19 example loads directly (no submenu) - Bump web package to 2.0.1
Removes the duplicated literal between pyproject.toml and __init__.py so the /api/health badge tracks the package version automatically.
…z wheel
`pip install ontoloviz` now ships the desktop GUI, the FastAPI server, and the
bundled web frontend as a single PyPI distribution — no optional extras, no
second package.
- move server/ontoloviz_server/ → src/ontoloviz_server/; both packages live
side-by-side under one wheel
- drop server/pyproject.toml + server/uv.lock; merge fastapi, uvicorn[standard],
httpx, pydantic and the dev extras into the root pyproject
- expose a second console script: `ontoloviz-server` (alongside `ontoloviz`)
- ontoloviz_server.__init__ now reads importlib.metadata.version("ontoloviz")
- bundle the production web build under src/ontoloviz_server/web_dist/ via
setuptools package-data; main.py mounts it as the SPA at `/` with an /api/*
guard, and gracefully skips when the directory is absent (dev mode)
- Makefile: `make build` runs pnpm build → embeds dist/ → uv build, producing
wheel + sdist; `dev-server` runs `uv run ontoloviz-server` from repo root
- move server tests to tests/server/; ruff config scoped to server + tests
- README + web/README updated to drop server/ references
- ontoloviz-server now accepts --host/--port/--workers/--reload/--proxy-headers/ --log-level (with ONTOLOVIZ_* env-var fallbacks). Defaults stay dev-safe (127.0.0.1, single worker, no reload). `--dev` re-enables hot reload for the Makefile's dev-server target. - CORS origins read from ONTOLOVIZ_CORS_ORIGINS; defaults to the Vite dev ports. Same-origin prod deployments leave the middleware dormant. - Multi-stage Dockerfile builds the web frontend, assembles the wheel, and installs it into a slim python:3.12 runtime. Non-root user, exposed :8000, /api/health healthcheck, prod-tuned ONTOLOVIZ_* defaults. - .env.example documents every server env var. - README gains a "Production launch" section with both bare-metal and container recipes.
- move 5 TSVs (atc_template, mesh_template, the 3 examples) from repo-root templates/ to web/public/templates/ — Vite bundles them into the SPA build, setuptools ships them in the wheel under web_dist/templates/, all served from /templates/*.tsv at runtime - drop the two pre-rendered Plotly demos (atc_example.html, mesh_example.html); the live SPA renders the equivalent and the static HTML exports were 13 MB combined — bloat with no upside - drop README rows for two custom_template_*.tsv files that never existed in the repo (broken raw.githubusercontent.com links) - LandingPage now surfaces all three example datasets (experimental + trial summary ATC, PubMed-mapped MeSH) plus the two empty templates - README "Templates and Examples" links rewritten to point at web/public/templates/ on master; one-line note documents the in-wheel path Wheel grows from 794 KB → 1.5 MB.
- OBO Foundry: full-width card with accent left-bar (live-fetch action) - Templates: demoted to inline filename links under primary CTA - Examples: 3-up cards with per-ontology sunburst thumbnails (ATC / MeSH) - Restore visible separators using text-subtle (footer + template links) - Uniform left-align across example cards regardless of description length - OboFoundryPicker: equal-height tiles, line-clamped descriptions, truncated URL
- Canonical source at branding/ (logo.svg, logo.png 256px, logo.ico
with 16/32/48/64/128/256 sizes); generated from rsvg-convert + magick.
- Consumer locations symlinked back to branding/ so there is a single
source of truth: web/public/logo.{svg,png}, src/ontoloviz/assets/
logo.{svg,png}, and the root-level logo.ico used by ontoloviz.spec.
- Web: favicon + apple-touch-icon links in index.html; landing page
crosshair replaced with the new mark.
- Desktop: Tk window sets iconphoto from assets/logo.png on startup.
- New SunburstTile reuses layoutSunburst + renderSunburst with a depth cap
for legible previews; no breadcrumbs/tooltip, click drills into detail
- New OverviewGrid renders one tile per subtree in a responsive grid
- Store gains viewMode ("overview" | "detail"); multi-subtree ontologies
default to overview, single-subtree skip straight to detail
- Header gets an Overview/Detail segmented toggle (hidden when only one
subtree exists)
- layoutSunburst takes an optional maxDepth cap, composable with focusId
- parse_obo / _build_ontology accept root_id and min_node_size. With root_id set, direct children become subtree roots (level 0, parent="") and anything outside the descendant set is dropped, mirroring the desktop GUI's HP:0000118 / DOID:4 / CHEBI:23367 / UBERON:0000061 defaults. Falls back to natural roots with a warning if root_id is absent. - /api/obo/fetch gains rootId / minNodeSize query params; /api/obo/parse reads them from the body. OboPreset + fetchObo + OboFoundryPicker thread the overrides through. - HPO preset now produces ~22 phenotype-system subtrees instead of one giant HP:0000001 sunburst. - /api/obo/fetch memoises results in an in-process LRU+TTL cache (8 entries, 24h) keyed on (url, root_id, min_node_size). Cap raised 50 -> 150 MB so chebi_lite (~53 MB) fits; full chebi.obo (~260 MB) remains rejected — we don't visualize the structure table. - ChEBI preset switched to chebi/chebi_lite.obo, matching desktop. - Landing background: replace tiled network/dot pattern with a single centered sunburst (rings + radial dividers) that reflects the actual visualization. Quieter opacity (0.05 / 0.18) so it sits behind copy. - Tests: 6 new (root_id split, missing-root fallback, min_node_size, parse body alias, fetch query param, cache hit, cache key isolation); autouse fixture resets the cache between tests.
- Compute the full partition once per subtree and project it through a moving FocusFrame instead of re-partitioning on every focus change. - Tween between focus frames over 450ms with ease-out-cubic, driven by rAF; respects prefers-reduced-motion (snaps instead of animating). - Hit-test against the most recently projected layout so hover/click track what is actually drawn mid-tween. - Clicking the focused slice now zooms one level up to its parent (no-op at the root). The breadcrumb still covers any-ancestor and full reset.
added 28 commits
May 26, 2026 14:18
Adds a TSV exporter that mirrors the legacy desktop app headers (parent-based and dot-separated formats) so files round-trip through the existing parser. The ExportMenu now accepts an optional ontology prop and surfaces the TSV option whenever a full ontology is loaded, including overview mode. Includes test coverage for both formats and the template-mode reset of counts/colors.
Replaces the thin top progress bar with a rotating conic-gradient arc plus pulsing glow around the chart panel while propagation is recomputing. The ring lives in a new .recomputing-ring utility class and animates its angle through a registered @Property custom value, falling back to the always-on box-shadow pulse when @Property isn't supported. Drives off the existing isRecomputing flag wired through LoadedView.
Passes the propagated ontology through Header into ExportMenu so the new OntoloViz-compatible TSV export is reachable on both detail and overview views. Also restructures the row-collection logic into per-format helpers with deterministic ordering, adds PNG scale options to the export menu, and extends test coverage.
- Inline JS runtime renders sunbursts client-side: click a slice to re-partition with it as the new root; click the focused slice or a breadcrumb to zoom out. - Overview HTML wraps each tile as a clickable group; clicking drills into a full-screen interactive sunburst with a back button. - Custom HTML tooltip (id, label, count, description) replaces the native SVG <title> hover. - Theme follows the app: ExportMenu snapshots useTheme() and stamps data-theme on <html>; runtime CSS variables drive both palettes. - Stage letterboxes to fit viewport; overview grid only constrains width and scrolls vertically for large ontologies. - Detail stage gets a framed border + soft shadow in both themes.
- New right-pane Export panel (PNG/SVG only) that takes over the main area: large live SVG preview + control rail with presets, scope, dimensions, theme overrides, per-element label styles, and burned-in title/caption. - Presets: Publication (light, serif), Presentation (dark, sans), Web (mirrors the live app theme via webThemeFor + useTheme). - ExportTheme threaded through svg.ts, png.ts, overview.ts, and render.ts; legacy HtmlTheme renamed so the static theme name is free. - Overview rendering gains label-position (above/below/overlay), tileBorder opt-in, per-label font size / bold / alignment, dynamic label-band layout, and proportional slice strokes that scale with figure size. - render.ts: background:null now preserves existing canvas pixels so the overview-tile bg paint isn't cleared to transparent (fixes black PNG interiors); strokeWidth is configurable. - ExportMenu dropdown keeps quick HTML/TSV exports and gains an "Export…" entry that opens the workspace. - useExportConfig zustand slice persists last-used config (version 3). - Export test suite extended with light-theme, font, label-position, and caption burn-in cases.
- ExportPanel: lock scope to active view (overview vs detail), drop scope chip - ExportMenu: hide subtree image rows in overview, overview image rows in detail; keep TSV in both - Rename dropdown entry to "Customize export… · presets, dimensions, …" so the path to the figure workspace is explicit
- give each overview label (id/count/name) its own above/below/overlay slot via `labelPositions`, replacing the single shared `labelPosition` - let overview exports omit selected subtrees via `excludedRootIds` - defer config/theme/ontology inputs to the export preview so the control rail stays responsive; show the recompute ring on the figure wrapper while the deferred SVG catches up - drop unused `format` field from ExportConfig; downloads still take the format directly from the clicked button
Reshape the count/color propagation controls ported from the tkinter
GUI into task-oriented language; store keys are unchanged.
- Fold the two 'Enabled' toggles into their mode pickers ('off' is now
the first choice), removing the separate enable/mode indirection.
- Replace jargon with plain labels (Counts/Color, 'Roll children into
parents', 'By count - per subtree', 'Neutral color', etc.) and give
each choice a one-line explanation of its effect.
- Bound the level sliders to the loaded ontology's real depth with an
'n / max' readout, and add a live sentence naming the affected levels
as the thumb moves (roll-up ceiling and color-from-depth).
- Hide 'Outermost nodes only' for non-MeSH data and the color scale
editor when colors come from the file.
Add a 'Ring thickness' settings section with one slider per ring (0.25x-3x of the uniform baseline), letting figure authors thin a busy outer layer or emphasize a structural one. Purely visual: the angular (count) encoding is untouched, so quantitative meaning is preserved. - layout: layoutSunburst takes optional ringWeights, remapping each ring's radial band by cumulative weight. Omitted/empty is byte-identical to before. - store: new layout.ringWeights slice with setRingWeight (pads intervening rings with the baseline) and resetRingWeights. - wire weights through every draw site for consistency: live sunburst, overview tiles, and all static/HTML export paths including the inline runtime's client-side re-partition. - fix pre-existing ColorStopEditor lint errors (React.PointerEvent under the new JSX transform) so the repo lints clean. - cover the remap and store padding/reset logic (14 new tests).
Templates were consolidated into web/public/templates in e81b64f, but the parity, parity-color, parse tests and the fixture generator still read the deleted REPO_ROOT/templates dir, causing ENOENT on every parity case. Verified the consolidation was a pure move (pre/post TSVs share MD5s), so existing fixtures remain valid; only the lookup path needed updating. Full web suite now 157/157, tsc clean.
…port
Detail-scope (single-subtree) exports gain optional labels derived live from
the focused root node — id, header (name), and description — each with
visibility, position (above/below/overlay), size, weight, and alignment.
- Extract shared label-band geometry into lib/export/labelBands.ts so the SVG
and canvas renderers agree on band reservation and line placement.
- Add SubtreeLabel{Flags,Positions,Styles} types + defaults (all off, so
existing subtree exports are unchanged until opted in); bump persisted
export-config version 6 -> 7.
- Make the panel's Labels section scope-aware: overview keeps id/count/name,
detail gets id/header/description with full style controls. Removes the
previously dead detail-scope toggles that the renderer never consumed.
- Cover the new geometry with unit tests and add layoutToSvg label-rendering
integration tests.
Give deep ontologies a single 'fatten center ↔ fatten edge' knob instead of requiring a per-ring slider drag for every layer. Because the sunburst normalizes ring bands by cumulative weight, only the inner→outer gradient is visible — so one taper value captures the meaningful bulk adjustment. - taper: new pure taperRamp(t, ringCount) maps t∈[-1,1] to a centered linear weight ramp; t=0 is byte-identical to uniform, ±1 lands rings at 1±0.75 (inside slider bounds, no clamping), middle ring stays on baseline. - store: setRingWeights bulk action replaces the whole weight array in one update (stores a copy); exports already read ringWeights, so no export wiring changed. - settings: TaperSlider above the per-ring list, shown only for ontologies with >=4 rings. Commits on release like the per-ring sliders; its knob is local UI state that re-centers whenever rings return to uniform (reset / new ontology). - header: swap the placeholder square brand mark for the /logo.svg image. - tests: 9 taperRamp cases (direction, symmetry, bounds, middle-ring invariance, clamping, degenerate counts) + 2 setRingWeights cases.
Ontology handoff:
- POST /api/ontology stores a pushed ontology under a 128-bit capability
token (in-process TTL+LRU); GET /api/ontology/{id} retrieves it or 404s.
- Frontend resolves ?session=<id> through the standard render pipeline and
strips the token from the URL after load.
Deployment tooling:
- Wheel-based install-service.sh / update-service.sh (systemd, single-worker,
hardened unit, idempotent, post-deploy SPA healthcheck); host needs no Node.
Reverse-proxy sub-path support:
- Configurable Vite base (VITE_BASE) + withBase() helper routes all asset,
/api, logo and template URLs base-relative so the SPA works under a prefix
(e.g. /ontoloviz/). Backend unchanged — the proxy strips the prefix.
Config hygiene:
- All deployment values via ONTOLOVIZ_* env with conventional defaults
(127.0.0.1:8000, base /); no hardcoded ports or hostnames in source.
Docs & tests:
- docs/RUNBOOK.md, docs/CONTRIBUTING.md, docs/ontology-handoff.md (+ example
payload); README pointers. Server endpoint + frontend fetchSession suites.
Bump version to 3.0.1.
- update-service.sh --build: preflight node/pnpm/uv, then run 'pnpm install --frozen-lockfile' before make build so updates work on a cold checkout and after dependency bumps. - vite.config: read VITE_BASE / dev port / API target via loadEnv, so a gitignored web/.env.production.local persists the sub-path base across rebuilds (no need to re-pass VITE_BASE; never committed). - install-service.sh: 'no wheel' error now documents the build-on-host flow. - RUNBOOK: add a build-on-prod section (one-time toolchain + persisted base).
- Default Vite base to relative ('./') so one bundle serves at the root or
any reverse-proxy sub-path (e.g. /ontoloviz/) with no build-time config;
VITE_BASE now only forces an absolute base (CDN).
- Route the session fetch through withBase and assert it in tests.
- Approve esbuild's postinstall via pnpm.onlyBuiltDependencies so prod's
non-interactive 'make build' (pnpm 11) no longer fails on ERR_PNPM_IGNORED_BUILDS.
- Drop the web/.env.production.local sub-path dance from RUNBOOK, handoff
docs, install-service.sh, and update-service.sh; add web/.env.example.
pnpm 10+ no longer reads the package.json "pnpm" field, so the esbuild build-script approval added earlier never took effect and prod kept hitting ERR_PNPM_IGNORED_BUILDS. Move onlyBuiltDependencies to its documented home in pnpm-workspace.yaml and drop the dead package.json field.
pnpm 11 removed onlyBuiltDependencies in favor of an allowBuilds map and
defaults strictDepBuilds=true, so the prior key was ignored and esbuild's
blocked build script made `pnpm install` exit 1 -- which in turn failed
`pnpm build`'s pre-run dependency check. Add allowBuilds: { esbuild: true }
for pnpm 11 and keep onlyBuiltDependencies for pnpm 10 dev hosts.
Confirmed on prod: pnpm 11 turned ERR_PNPM_IGNORED_BUILDS into a fatal exit-1 that killed `pnpm build`'s pre-run dependency check. The earlier allowBuilds/onlyBuiltDependencies keys were inert because the cached "Already up to date" install never re-evaluated them. Set strictDepBuilds=false so an unreviewed esbuild build script is a warning, not a hard failure -- Vite resolves the @esbuild/<platform> binary directly, so esbuild's postinstall is not needed to produce the bundle. Keep allowBuilds (pnpm 11) and onlyBuiltDependencies (pnpm 10) so clean installs still approve esbuild outright.
Under sudo, python3 resolves to root's /usr/bin/python3.13, whose ensurepip lives in the separate python3-venv package -- so `python3 -m venv` failed on prod even though the user's interactive python could create venvs. Create the venv with `uv venv --seed` when uv is available: uv carries its own pip wheels (no system ensurepip needed) and --seed keeps pip inside the venv so update-service.sh's `pip install` path is unchanged. Resolve uv by absolute path because sudo strips the login PATH, and fall back to `python3 -m venv` on hosts that have python3-venv but no uv.
Behind a containerized reverse proxy (nginx-in-Docker via host.docker.internal), a 127.0.0.1 bind is unreachable and 502s. Default ONTOLOVIZ_HOST to 0.0.0.0; set 127.0.0.1 explicitly for host-local-only deploys. - install-service.sh: reconcile explicitly-passed HOST/PORT/PROXY_HEADERS into an existing /etc/ontoloviz.env. The file was write-once, so re-run overrides were silently ignored — the trap that stranded the service on 127.0.0.1:8000. Operator customizations and defaults-only re-runs are left untouched. - update-service.sh: warn when bound to 127.0.0.1, since the host-local healthcheck passes even when the proxy cannot reach the service.
Bare `./update-service.sh` now does git pull + pnpm install + make build + install + restart (previously default was wheel-only). Drop the `--build` flag; pass a wheel path or `--wheel` to skip the build on Node-less hosts. - flip mode selection: build is default, wheel mode is the opt-in - update header usage, toolchain-preflight and no-wheel error messages - sync docs/RUNBOOK.md update/rollback section
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.
Adds a React/TypeScript based web-app with a FastAPI backend server, plus deployment tooling
New Features
web/) - Vite + React + TS; Complete OntoloViz rewrite using d3.jssrc/ontoloviz_server/) - FastAPI app with health, models, OBO and ontology-handoff routes; DockerizedTests
Bumped coverage by adding parse / layout / color / propagation / taper / session / store tests