Skip to content

Davereinhart/gnomad id search - #707

Merged
davereinhart merged 10 commits into
release-2026.2.4.1from
davereinhart/gnomad-id-search
Aug 7, 2026
Merged

Davereinhart/gnomad id search#707
davereinhart merged 10 commits into
release-2026.2.4.1from
davereinhart/gnomad-id-search

Conversation

@davereinhart

Copy link
Copy Markdown
Contributor

This pull request introduces several improvements and new features to the variant search experience, particularly around searching by gnomAD variant IDs and handling gene symbol searches. It also includes UI enhancements and code refactoring for clarity and maintainability.

Variant Search Improvements

  • Added support for searching by gnomAD variant IDs (getAlleleByGnomad), including automatic detection of the correct genome assembly (GRCh38 or GRCh37), fallback logic, and user interface to switch assemblies if needed. The UI now clearly reports which assembly was used and allows users to retry with the other assembly. [1] [2] [3]
  • Enhanced the "Any" search option to detect the type of identifier entered and report how the input was interpreted. This provides better feedback to users about their query. [1] [2]

Gene Symbol Search Improvements

  • Improved gene symbol searches: when a valid gene symbol is entered, users are taken directly to the gene page, bypassing the variant search screen, which streamlines navigation and avoids unnecessary history entries.

API and Data Structure Updates

  • Updated the ClinGen API methods: getAlleleByDbSnp and getAlleleByClinVar now return arrays of alleles instead of a single allele, improving consistency with the API and supporting multiple results.
  • Added a comprehensive test suite for the new getAlleleByGnomad function, covering various edge cases and error handling.

UI and Styling Enhancements

  • Added new color variables for search types (including gnomAD and gene) for consistent theming across the application.
  • Refactored variant result cards to render as plain text when a ClinGen ID is not available, improving clarity for unregistered variants. [1] [2]

Default Search Behavior

  • Changed the default search type on the home screen from "HGVS" to "Any", making the search experience more flexible and user-friendly. [1] [2]

These changes collectively enhance the search experience, provide clearer feedback to users, and improve code maintainability.

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.
@davereinhart davereinhart linked an issue Aug 6, 2026 that may be closed by this pull request
@bencap
bencap changed the base branch from main to release-2026.2.4.1 August 6, 2026 20:13

@bencap bencap left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Dave! We should address the second and fourth comments below prior to merging, but it's going to be really nice to have a search field that handles all our identifiers from a single catch-all search.

I didn't really have a great idea for the pills spilling over to the second line. In the long run, I think we'll probably be happiest if we unify the homepage and the MaveMD page into a shared MvVariantSearchBar component with the dropdown style selector. Don't feel like you have to make that change here though, its fine with me if we leave the pills on multiple lines and track that as a follow up issue.

I was also thinking about the regEx you built out here and it reminded me of the routeToVariantSearchIfVariantIsSearchable function in search.ts. I thought it might make sense to extract or import detectSearchType there and use it within the routing function. The only thing that gives me pause is thinking that plain integers should remain on that page and that gene symbols probably shouldn't preemptively route to the gene page within the data set search flow. This also seems fine to defer if it's a pain.

Comment thread src/assets/app.css Outdated
Comment thread src/components/screens/SearchVariantsScreen.vue
Comment thread src/components/screens/SearchVariantsScreen.vue
Comment thread src/components/screens/SearchVariantsScreen.vue Outdated
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

Copy link
Copy Markdown
Contributor Author

Thanks for the review and detailed comments @bencap! I addressed each of them and also added 0085ad3 which was not covered here. It is a global change, so wanted to check if you know of any cases where we would not want the vertical scroll position reset when navigating to a new page.

I can look into extracting detectSearchType too, but the cases you mentioned do sound like it might need more changes before using it in the routing function so it might be worth treating as a separate issue.

@bencap bencap left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thanks Dave! I can open a couple issues for the search RegEx harmonization and consolidating the components.

@davereinhart
davereinhart merged commit 06fd8a7 into release-2026.2.4.1 Aug 7, 2026
1 check passed
@davereinhart
davereinhart deleted the davereinhart/gnomad-id-search branch August 7, 2026 23:28
@bencap bencap mentioned this pull request Aug 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add gnomAD genomic coordinate search to MaveMD

2 participants