Add a DANDI Atlas entry to the Open with menu - #2873
Open
bendichter wants to merge 1 commit into
Open
Conversation
The atlas viewer at atlas.dandiarchive.org can display a Dandiset's electrode locations against a reference brain atlas, but there was no way to reach it from the Dandiset landing page. This adds a "DANDI Atlas" entry to the "Open with" menu that deep links into the viewer. The entry only appears for Dandisets the viewer can actually display. dandi/dandi-atlas#27 published a per-atlas list of Dandiset identifiers in atlases_index.json, so the client fetches that file and shows the entry only on a hit. An unsupported identifier is not an error in the viewer: it silently drops the user on the atlas overview, so gating the link is better than always showing it. The index is fetched once per session and shared across Dandisets. A failed request is logged and the entry is omitted, since the rest of the page does not depend on it. Closes #2870 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member
Author
Screen.Recording.2026-07-30.at.3.38.58.PM.mov |
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.
What
Adds a "DANDI Atlas" entry to the "Open with" menu on the Dandiset landing page, linking to
https://atlas.dandiarchive.org/?atlas=<key>#dandiset=<id>. The entry only appears for Dandisets that the atlas viewer can actually display.Closes #2870.
Why the entry is gated
An identifier the viewer does not know about is not an error there:
applyURLStategates ondandisetToStructures[did], so the deep link silently drops the user on the atlas overview with no explanation. Showing the entry unconditionally would produce a dead-end link on most Dandisets, so it is better to show it only when the destination will work.dandi/dandi-atlas#27 added a
dandisetsfield to each atlas record indata/atlases_index.jsonfor exactly this. That file is 2.9 KB and is served withaccess-control-allow-origin: *, so the client can fetch it directly.How
web/src/utils/atlas.tsfetches the index once per session and inverts it into aMapfrom Dandiset identifier to atlas. The component looks up the current identifier and renders the entry only on a hit. The shape followsutils/doi.ts: bareaxiosagainst a full URL, and acatchthat logs and fails safe rather than throwing, since the rest of the page does not depend on this link. A failed request clears the cache so a later navigation retries.Two details worth calling out:
A Dandiset can belong to more than one atlas. For example
000947is registered against both D99 and NMT. #2870 says linking to one of them is fine, so the first match in index order wins. This is deterministic but arbitrary; if a preferred atlas per Dandiset is wanted later, that belongs in the index rather than here.The entry is restricted to production. The viewer only indexes production Dandisets, and identifiers collide across deployments: sandbox
000017is unrelated data from the000017in the Allen CCF list, so linking it would send the user to the wrong dataset. The check ismetadata.urlstarting withhttps://dandiarchive.org/, matching how the adjacent Neurosift URL already detects the instance. Usingmetadata.urlrather thanwindow.location.originmeans a locally served client pointed at the production API still gets the link, which is what makes the verification below possible.Verification
Ran the dev client against the production API and drove it with Playwright:
000022(Allen CCF)?atlas=allen_ccf#dandiset=000022000947(D99 + NMT)?atlas=d99#dandiset=000947000004(no atlas)000022reproduces the example URL from #2870 exactly. Loading that URL in the viewer resolves correctly: it selects Allen CCF, opens the "Dandiset 000022" panel with 26 subjects and 56 brain regions, and highlights the relevant regions.Then restarted against the sandbox API and loaded sandbox
000017, whose identifier is in the Allen CCF list. The entry is correctly absent while Neurosift still renders, confirming the instance gate.npm run lintandnpm run type-checkboth pass.Note for reviewers: the deploy preview cannot show this
netlify.tomlbuilds deploy previews against the sandbox API (context.deploy-preview.environment), and the entry is restricted to production for the reason above, so it is correctly absent everywhere on the preview link. I confirmed this on the preview itself: sandbox000017shows Neurosift but no atlas entry. That is the intended behavior, not a broken build. To see the entry, run the client locally withVITE_APP_DANDI_API_ROOT=https://api.dandiarchive.org/api/and open000022.On tests
I did not add an e2e test. The suite runs against a local deployment, where the production gate correctly suppresses the entry, so the positive case cannot be exercised without stubbing the Dandiset info response to claim a production
metadata.url. A test that only asserts the entry is absent would pass just as well if the feature were entirely broken, which seemed worse than no test. Happy to add the stubbed version if you would rather have the coverage.🤖 Generated with Claude Code