Add reusable linked-grid template + FileManager results store#395
Add reusable linked-grid template + FileManager results store#395t0mdavid-m wants to merge 9 commits into
Conversation
…ager + demo) - src/view/grid.py (NEW): tool-agnostic render_linked_grid(layout, builders, state_key, ...) + parameterized LayoutManager (folds the two FLASH*LayoutManager classes: <=3 cols, N rows/experiments, side-by-side, validation, JSON save/load). builders = comp_name -> zero-arg factory -> BaseComponent over one shared StateManager. No data/hashing (moved into Insight components). AST-verified: zero MS/FLASH identifiers. - src/view.py -> src/view/__init__.py (package; preserves raw_data_viewer's `from src import view`). - src/workflow/FileManager.py: ported the (dataset_id, name) results store + get_results(as_path=True) + result_path() returning the .pq path to feed Insight data_path=. - src/common/common.py: show_linked_grid(layout, builders, *, tool, side_by_side) one-liner (one StateManager per experiment). - content/visualization_template.py (NEW) + app.py registration: Table<->LinePlot<->Heatmap<-> SequenceView linked-grid demo + LayoutManager + side-by-side over example-data/insight/ parquet. - tests/test_view_grid.py (+13): construct-smoke for all 4 components, render_linked_grid, show_linked_grid, LayoutManager round-trip, and the data_path subprocess path. Verified: pytest 74 passed/2 skipped; parse + construct-smoke green. https://claude.ai/code/session_017kD4FyAsNvW6VFTZwVvSne
- _handle_setting_buttons: validate the trimmed (internal-name) uploaded layout BEFORE expanding, matching the oracle handleSettingButtons (the (... needed) dependency check is a no-op on the trimmed form; it fires later at Save time). Validating expanded labels wrongly rejected hand-crafted uploads. - drop unused typing imports (Any, Sequence).
test_show_linked_grid_one_state_manager_per_experiment compared id() of StateManagers it didn't retain, so GC could reuse an id within a run and make the id-based set flaky in full-session order (passed in isolation / the gate, but could report 1 distinct id instead of 2). Assert on the stable _session_key (demo__exp0 / demo__exp1) — the actual one-StateManager-per-experiment invariant. Verification harness only; no change to any reviewed unit.
Round-5 finding 3-grid-003: uploading a layout JSON with a wholly-empty experiment ([]) wiped the whole layout. expand() dropped the empty experiment, so len(layout) < num_experiments(=len(uploaded)) tripped the reset-on-count-mismatch and replaced the upload with blanks. The oracle handleSettingButtons inline-expand keeps an empty experiment as a [] stub, so the counts match and nothing is reset. Add expand(drop_empty_experiments=) and pass False on the upload path (edit mode still drops empties). Test added.
… 4 Dockerfiles)
The template viewer page (visualization_template.py) imports openms-insight, but it
was not installed by any Dockerfile. Add an insight-build stage (node:21) to all four
Dockerfiles (Dockerfile{,.arm}, Dockerfile_simple{,.arm}) that clones the openms-insight
branch claude/kind-heisenberg-u6dVm, builds its Vue bundle, syncs dist into the package,
then pip-installs the source tree (hatchling force-includes the bundled dist). Installs
from source so no PyPI publish is required.
…esh-clone fix) In a fresh clone openms_insight/js-component/ does not exist (only held the gitignored dist/), so cp had no parent dir. mkdir -p it first. Validated against a fresh clone: clone -> npm build -> sync -> pip wheel bundles the Vue dist (incl. index.js).
|
Warning Review limit reached
More reviews will be available in 59 minutes and 58 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (4)
📒 Files selected for processing (14)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ayer) The migration added module-level "import polars as pl" to src/workflow/FileManager.py (parquet/as_path support for the Insight data-layer), but polars was not in requirements.txt -- only pyarrow (transitive via streamlit) was. The GUI test suite (pytest test_gui.py) installs requirements.txt and imports FileManager via the Workflow pages, so all 12 launches failed with "No module named 'polars'". Pin polars==1.41.2 (the proven version; FLASHApp uses polars>=1.0.0). Note: requirements.txt is pip-compiled; the external pyproject.toml source should also list polars so future recompiles keep it.
Summary
Introduces a production-ready, tool-agnostic linked-grid visualization stack for OpenMS-Insight components, along with a SQLite-indexed results store in FileManager. This enables any downstream app (FLASHApp, quantms-web, etc.) to render cross-linked multi-panel dashboards with a single function call, while persisting layouts and managing large datasets efficiently.
Key Changes
New:
src/view/grid.py— Reusable Linked Grid Templaterender_linked_grid()— Core function that renders one experiment's grid of OpenMS-Insight components with a shared StateManager for cross-linking (clicks in one panel filter others). Enforces ≤3 columns per row (oracle invariant) and supports per-component height overrides.LayoutManager— Full UI for editing/saving/uploading grid layouts. Parameterized by component vocabulary and storage keys so it works identically across FLASHDeconv, FLASHTnT, FLASHQuant, etc. Persists trimmed internal-name layouts + side-by-side flag to FileManager.StoreProtocol — Minimal structural interface (get_results, store_data, result_exists, remove_results) so the grid never imports concrete FileManager; any object implementing these four methods works.Distills two near-identical FLASH manager implementations into one frozen, vendorable module with zero tool/MS-specific knowledge.
Enhanced:
src/workflow/FileManager.py— SQLite-Indexed Results Storestore_data(dataset_id, name_tag, data)— Automatically detects format and stores:.pq) for performance.pkl.gz)(dataset_id, name_tag)for fast lookupget_results(dataset_id, name_tags)— Retrieves stored data with proper format restoration (pandas DataFrame, polars LazyFrame, or pyarrow Dataset)result_path(dataset_id, name_tag)— Returns on-disk parquet PATH for Insight components'data_path=argument (subprocess preprocessing + disk cache, no in-memory load)store_file()/parquet_sink()— File storage with atomic rename and SQLite registrationNew:
src/common/common.py::show_linked_grid()render_linked_grid()that owns multi-experiment + side-by-side page concernside_by_side=True; otherwise stacks with dividersNew:
content/visualization_template.py— Linked Grid Demo Pageexample-data/insight/New:
example-data/insight/— Example Fixtures_make_example.py— Generator script for tiny, hand-built parquet files (20 scans, 400 peaks, 3 sequences)spectra.parquet— Master table (scan_id, rt, ms_level, precursor_mz, n_peaks)peaks.parquet— Per-peak long format (scan_id, peak_id, mass, intensity, is_annotated, ion_label)heat.parquet— Peak map (scan_id, rt, mass, intensity, peak_id)sequences.parquet— Per-scan sequences (scan_id, sequence, precursor_charge)Stable IDs enable cross-linking: peak_id is globally unique, reused across
https://claude.ai/code/session_017kD4FyAsNvW6VFTZwVvSne