SpectraMax: Parse wavelengths as an array; truncate wavelength badges with hover tooltip - #37
Merged
Conversation
Plate reader runs with multiple wavelengths (e.g. 750/700/650/600 nm) were flattened into a single comma-joined `wavelength` field, which meant filter dropdowns and metadata badges couldn't treat each wavelength independently. Switch the parser to emit a `wavelengths` array of numeric strings, mirroring the Azure 600 Gel Doc shape, and update the web app to render, filter, and color-code each wavelength as its own badge. JSONB containment (`@>`) is now used for the wavelength filter, consistent with gel-doc filtering.
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Summary
Two related improvements to multi-wavelength run metadata:
wavelengthmetadata into awavelengthsarray, mirroring the Azure 600 Gel Doc shape. SpectraMax.xlsfiles can declare multiple wavelengths (e.g.750 / 700 / 650 / 600), but we were collapsing them into a single"750 nm, 700 nm, ..."string that couldn't be filtered or color-coded per-wavelength. Metadata now stores numeric strings (["750", "700", "650", "600"]) and the UI owns display formatting.maxVisiblebadges render inline, followed by a+Noverflow badge; hovering the cell reveals every badge on a single row in a tooltip.Changes
Lambda / parser
lambda/src/data_hub_lambda/spectramax_plate_reader/utils.py:parse_metadatanow returns"wavelengths": list[str](numeric strings, nonmsuffix) instead of"wavelength": str. Return type widened todict[str, object].lambda/tests/spectramax_plate_reader/test_parse_metadata.py) and integration tests (lambda/tests/integration/test_lambda_api.py) to assert the new shape. Addedtest_four_wavelengthsto cover multi-wavelength parsing.Web app — API
web-app/lib/api/instrument-runs.ts: wavelength filter switched from->>'wavelength' = $valueto a JSONB containment check (->'wavelengths' @> '[$value]'::jsonb).getPlateReaderFilterOptionsnow pulls distinct values from the array viadistinctMetadataArrayValues("wavelengths"). Removed"wavelength"fromALLOWED_METADATA_KEYS;"wavelengths"was already allow-listed for the gel doc.Web app — UI
TruncatedBadgescomponent +sortWavelengthshelper inweb-app/components/runs/metadata-badges.tsx(re-exported fromruns-table/metadata-utils.tsx). Extracted aBadgeRowhelper shared withMetadataArrayBadges.plate-reader-runs-table.tsx: column renamed "Wavelength" → "Wavelengths", now rendersTruncatedBadges(maxVisible={1}) with per-wavelength colors, and sorts wavelengths numerically (cells + filter dropdown).gel-doc-runs-table.tsx: wavelengths column usesTruncatedBadges(maxVisible={1}, numeric sort); wavelength-colors column usesTruncatedBadges(maxVisible={2}, no sort).run-metadata-badges.tsx: plate reader + gel doc run-detail sections readwavelengthsas an array (row label flips between "Wavelength" / "Wavelengths"), appliesbuildWavelengthColorMapfor consistent per-wavelength colors, and sorts numerically.Breaking changes
wavelengths: string[]instead ofwavelength: string. Existing rows ininstrument_runs.metadatastill carry the old"wavelength"key and will render as—in the wavelengths column until they're reprocessed. No DB migration required (metadata is JSONB), but consumers readingmetadata.wavelengthfor SpectraMax need to switch tometadata.wavelengths.wavelengthfilter query param is unchanged externally but now maps to an array containment query server-side — no action needed for clients.Driveby changes
sortWavelengthshelper (ascending numeric, non-numeric values pushed to end) so the runs table, filter dropdown, and run-detail sections stay consistent.BadgeRowout ofMetadataArrayBadgesso the tooltip and inline renderers share layout code.Testing
make check-all(ruff, pyright, prettier, eslint, tsc) passesuv run pytest lambda/tests/spectramax_plate_reader/ lambda/tests/integration/ -vpasses, including newtest_four_wavelengthsuv run data-hub-process spectramax <sample.xls>emits"wavelengths": [...]JSON<first> +Nwith a hover tooltip showing all wavelengths in ascending numeric orderwavelengthsarraywavelengthsarray