Release 2026.2.4.1 - #714
Open
bencap wants to merge 25 commits into
Open
Conversation
Add gnomAD IDs (e.g. 17-7676154-G-C) as a search type on the MaveMD variant search screen and in the homepage hero search. A gnomAD ID does not name the reference genome its coordinates belong to, so getAlleleByGnomad translates it into genomic HGVS and resolves it against GRCh38 first, falling back to GRCh37 when the registry rejects the position with IncorrectReferenceAllele. Resolving HGVS is used in preference to the registry's gnomAD cross-reference index, which only covers variants ClinGen has ingested a gnomAD record for and so misses registered alleles such as X-41334274-A-C. - Add lib/gnomad with a GRCh38/GRCh37 RefSeq chromosome accession table and VCF-style to HGVS conversion covering substitutions, insertions, deletions and delins - Add getAlleleByGnomad to the ClinGen API module - Add gnomadIdRegex alongside the other search identifier patterns - Add the gnomAD search type to SEARCH_TYPE_OPTIONS, and its type, colors and placeholder to the homepage hero search - Add the gnomAD color tokens to the theme - Correct getAlleleByDbSnp and getAlleleByClinVar return types to ClinGenAllele[], which the /alleles endpoint has always returned Every accession in the table was verified against NCBI (accession to chromosome and assembly) and against the ClinGen registry (that each GRCh38/GRCh37 pair describes the same locus).
A gnomAD ID does not name the reference genome its coordinates belong to, and the same coordinates can be valid under both assemblies while naming a different variant in each: 1-1000001-G-T resolves under GRCh38 and GRCh37 to loci 64,620 bp apart. Searching one silently took the first assembly that resolved, so an ID taken from gnomAD v2 could return a confidently wrong answer with nothing to indicate it. Results for a gnomAD ID search now report the assembly the coordinates were read under, alongside the HGVS that was resolved, with a button to re-read the same ID under the other assembly. - Return the resolving assembly from getAlleleByGnomad, and accept one to read under, which skips the fallback and lets failure propagate - Thread a forced assembly through defaultSearch so switching reuses the existing search and MaveDB lookup path - Report coordinates that do not match an assembly's reference sequence as a warning naming the base actually found there, rather than surfacing the registry's IncorrectReferenceAllele as an error - Show alleles the registry resolved but has not registered, which it answers with a blank node id rather than a CA id, instead of discarding them as no result; this also affects HGVS searches for unregistered variants - Render one card header for registered and unregistered alleles, so both show their GRCh38 and GRCh37 coordinates
Make "Any" the default search type on the MaveMD variant search screen and the homepage hero. It matches the search string against the identifier patterns already defined for the specific types, then takes that type's usual path, so nothing about the individual searches changes. Detection order matters where those patterns overlap. A VRS digest also satisfies the deliberately loose HGVS pattern, which asks only for an identifier, a colon and a description, so it is recognized first. A bare number is a ClinVar Variation ID only once the more specific forms have been ruled out, so a dbSNP rsID written without its rs prefix reads as ClinVar and still needs the dbSNP type chosen explicitly. Because the selected type stays "Any", the results report which type the string was taken to be, as a chip in that type's colour, so a reading like that one is visible rather than silent. - Add detectSearchType alongside the identifier patterns it tries - Resolve "Any" to a concrete type at the top of fetchDefaultSearchResults, leaving every existing branch untouched - Add the "Any" type, colours and placeholder to both search screens, and point the search type fallbacks at it - Show the detected type in the results header, inside the existing live region so it is announced with the result count - Size the search type tabs to match the example chips below the search bar
Add "Gene symbol" as a search type on the MaveMD variant search screen and the homepage hero. Such a search trims and uppercases the string and resolves to the existing gene page at /genes/:symbol rather than looking up an allele, leaving GeneView to report a symbol it does not recognize. The route is replaced rather than pushed. The search screen re-runs its search from the query params on mount, so a pushed entry would send the back button here and immediately forward again to the gene page. Gene symbols are also detected by the "Any" search type. Any bare word resembles a symbol, so the pattern is tried only once every more specific identifier has been ruled out. Two consequences follow: a symbol that collides with a variant identifier loses to it, so CA1-CA14 and RS1 need the gene symbol type chosen explicitly; and "Any" now rarely reports an unrecognized identifier, since a string it cannot otherwise place resolves to a gene page that reports the symbol as not found. - Add geneSymbolRegex and try it last when detecting a search string - Navigate to the gene page from the search screen, with the symbol standardized to uppercase - Add the gene symbol type, colours, examples and placeholder to both search screens - Say that "Any" accepts gene symbols in its placeholder, which the search screen now takes from the shared placeholders rather than from an example
A gene symbol search replaced the variant search screen's history entry with the gene page, so the back button skipped past it. Pushing instead is no better on its own: that screen re-runs its search from the query params on mount, so returning to a recorded gene search bounced the user straight forward to the gene page again. Searches started from the homepage had a further problem, routing through the variant search screen and leaving a page the user never asked for between the two. Handle a gene symbol before the search is recorded in the query params, strip it from the entry being left behind, and push the gene route; and send the homepage straight to the gene page. The back button now returns where the search was started from, with nothing left to re-trigger: homepage Home -> gene page, back -> Home search screen /mavemd -> gene page, back -> /mavemd, search cleared link or bookmark /mavemd?search=BRCA1 back -> /mavemd, no re-run - Add geneSymbolSearchTarget, which resolves the search type and standardizes the symbol, so both screens decide this the same way - Move gene symbol handling out of fetchDefaultSearchResults, which gene searches no longer reach, and into defaultSearch ahead of the query sync - Await defaultSearch in searchForText and only record the search while still on the search screen, so a gene symbol example no longer races the navigation and rewrites the gene page's query params
Clicking a gene symbol example did nothing. searchForText selected the search type, reset the form and set the search text before searching, and each of those steps queued a query param rewrite of its own — four in all, plus a watcher clearing the search text mid-flight. Vue Router aborts an in-flight navigation when a new one starts, so the push to the gene page lost the race. Resolve the example up front and navigate before touching any search state. This covers gene symbol examples and any "Any" example that detects as one, and leaves every other example on the existing path. It also makes the previous commit's guard against recording a search after navigating away unreachable, since defaultSearch can no longer navigate from here, so that guard is removed again.
Add unit tests for the pure functions behind the "Any", gnomAD ID and gene symbol search types. The ambiguities these encode are much of the point: a bare number resolves to a ClinVar Variation ID rather than an unprefixed dbSNP rsID, CA1-CA14 and RS1 lose to the ClinGen and dbSNP patterns despite being real gene symbols, and a hyphenated string cannot be told apart from a symbol like HLA-A. Each is named in a test so it cannot drift unnoticed. - detectSearchType: the order it tries the patterns in, and what it returns for a string resembling nothing supported - geneSymbolSearchTarget: standardization, and that it hands a malformed symbol back for its caller to reject - getAlleleByGnomad: the GRCh38 to GRCh37 fallback, reads under a forced assembly, and which failures propagate rather than trigger a retry - Search configuration: that every hero search type has a colour, which the homepage dropdown indexes without a fallback, and that each documented example resolves to its own type gnomadIdRegex is already exercised through parseGnomadId in gnomad.test.ts, so it is tested directly only where that cannot reach: parseGnomadId also gates on the chromosome table, whereas detectSearchType applies the pattern on its own.
Give the "Any" search type sage and hand its slate to HGVS, so the search bar reads as brand-coloured on first load rather than neutral grey. Nothing tied HGVS to sage. Rename the token to --color-hgvs, following the name-by-search-type convention in that block. "Any" now points straight at --color-sage, and because SEARCH_COLORS.any is also the fallback for an unrecognized search type, that fallback returns to sage as well.
Address review feedback on #707. The results described the current form rather than the last search. Typing a new identifier rewrote the banner beneath the previous results, and a reading that failed because the position lies past the end of the chromosome still claimed the reference sequence did not match, because the template had no way to tell the two apart. Record the reading rather than the assembly alone: the ID as searched, the assembly it was read under, and how the registry answered. The error handler classifies IncorrectReferenceAllele and IncorrectHgvsPosition and threads that verdict through, so the template can name the real reason instead of reaching into the search box. - Hold {id, assembly, mismatch} rather than a bare assembly, and derive the banner from the recorded ID - Tailor the empty state to the kind of mismatch, and show the banner only for a reading that resolved, so it no longer contradicts the message below it or duplicates its button - Let the search type watcher run before an example fills the box, so choosing an example from another type leaves the text visible
The history API does not scroll and no scrollBehavior was configured, so every route change left the window where the previous page had it. Arriving at a gene page from a search made it obvious: the search screen scrolls its results into view, and the gene page then opened part way down. Scroll to the top for a new page, restore the saved position on back and forward, honour hash targets, and leave same-path navigation alone — the search screens mirror their state into the query string, and those navigations are not new pages.
Davereinhart/gnomad id search
…deScoreSetDropDownMenu Debug the dropdown menu of superseding score set shows private score sets problem.
- Extract `getErrorResponse` out of `api/mavedb/index.ts` and add `describeRequestError` alongside it in the new `src/lib/errors.ts`, replacing the ad hoc `extractErrorDetail` in ScoreSetCalibrationsView - Update all call sites to import from `@/lib/errors` instead of `@/api/mavedb` - Add unit tests covering both exported functions
Add use-csv-namespaces.ts and MvCsvColumnDialog.vue: a composable and dialog that fetch a score set's or variant's available CSV column namespaces from the new discovery endpoints and let a user pick which to include, replacing the score-set custom-download dialog's hand-picked checkbox list (scores/counts/mappedHgvs/etc.) that mapped to query params the API never actually read. Sections are grouped and labeled by the server (Measurements, Annotations, Clinical interpretation, Provenance) rather than hand-maintained client-side, and split by owning score set when a variant's calibrations span more than one. Defaults come from the API's selectedByDefault flag, so a research-use-only or rangeless calibration is offered but opts in explicitly. Wire it up in two places: - MvVariantPreview.vue's "Custom Data" dialog now uses it for score-set downloads instead of the old checkbox dialog - VariantScreen.vue gets a new "Download variant CSV" control backed by the variant-level CSV endpoint, split from the existing VA-Spec annotation downloads since they're a different kind of artifact (flat table vs. nested standard objects); use-variant-lookup.ts gains downloadVariantCsvFile and a shared downloadInProgressLabel Update openapi.d.ts for the new AvailableCsvNamespace / CsvNamespaceGroup schemas and endpoints, and switch score-sets.ts / variants.ts's CSV requests from drop_na_columns and include_post_mapped_hgvs to drop_unused_hgvs_columns and the namespace list, matching the API's new parameter names.
Fix streamAnnotationsInto (use-score-set-downloads.ts) accumulating NDJSON chunks as decoded strings: decoding to UTF-16, then joining, then building a Blob from the result meant a large pathogenicity-statement download held roughly five copies of the payload in memory at once and could run the tab out of it. Accumulate raw Uint8Array chunks instead and build the Blob directly from them, and count newline bytes rather than decoding to track progress. Also make a truncated stream (fewer lines than X-Total-Count) throw instead of silently saving a partial file, since the response has already started by the time that could be detected. Replace the per-feature annotatedDownloadInProgress/Progress state with a single fileDownloadLabel/fileDownloadProgress pair shared by every download this composable offers (scores, counts, mapped variants, custom data, and the VA-Spec streams), via a withIndicator() wrapper that also prevents two downloads running concurrently. Progress is indeterminate except for the VA-Spec streams, which can count records against X-Total-Count. Wire the shared indicator into ScoreSetDownloads.vue as one progress bar under the button row instead of one hung off the annotated-variants split button, disable every download button while any download is in flight, and add reportingFailure() so a rejected download surfaces a toast instead of an unhandled promise rejection in the console. Switch the custom-data dialog to MvCsvColumnDialog, matching MvVariantPreview and VariantScreen.
Also includes incidental reformatting.
Fills the annotations card's "Population Frequency" column, until now a "Data coming soon" placeholder. gnomAD is linked to a single mapped variant by ClinGen allele ID, so the frequency is a direct assertion about the measured allele rather than an aggregate over related variants. - Add MvGnomadSummary: AF with the AC/AN behind it, FAF95 with the genetic ancestry group attaining it, and a deep link to the gnomAD variant page, bottom-aligned so provenance lines up across the card's columns. - Read the record from the score set's variant data CSV via gnomadFromVariantRow, which normalises the namespace's NA sentinels. A variant absent from gnomAD reports as having no record, not zero frequency. - Derive GnomadFrequency from the generated OpenAPI schema, so renaming or retyping a field on the API model breaks compilation here. - Split HISTOGRAM_VARIANT_DATA_NAMESPACES into SCORE_SET_CHART_NAMESPACES and VARIANT_PAGE_NAMESPACES. One list fed two screens under a name describing neither, and only the variant page reads gnomAD, so the score set charts no longer fetch seven unused columns on every row. Requires the widened gnomad CSV namespace in the API.
…tate The API now reports a variant it cannot annotate as a record carrying an error object instead of letting the exception truncate the body. A download containing those records is complete and worth saving, but treating it as a clean export would misrepresent it. Tally error records as the stream arrives and raise a warning toast naming the count. Each chunk is decoded to scan its lines and then dropped, so only one chunk plus a partial line is ever live and the body is still retained as bytes -- decoding the whole payload is what previously ran the tab out of memory. Detection prefilters on a substring and parses only candidates, since these records nest deeply and parsing every one of a large stream is slow.
feat(ui): report annotation-stream variants the server could not annotate
bencap
marked this pull request as ready for review
August 12, 2026 21:53
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.
Features
Bug Fixes
Maintenance
N/A