Skip to content

feat: Neuroglancer Views cart pipeline (PR 5a, ngviews-05a-cart-pipeline) - #426

Draft
allison-truhlar wants to merge 16 commits into
ngviews-04-views-pagefrom
ngviews-05a-cart-pipeline
Draft

feat: Neuroglancer Views cart pipeline (PR 5a, ngviews-05a-cart-pipeline)#426
allison-truhlar wants to merge 16 commits into
ngviews-04-views-pagefrom
ngviews-05a-cart-pipeline

Conversation

@allison-truhlar

Copy link
Copy Markdown
Collaborator

Neuroglancer Views — PR 5a (ngviews-05a-cart-pipeline)

Stacked on #425 (ngviews-04-views-page). Read-only scope. PR 5 was split into 5a + 5b; this is 5a — the file-browser → Layer Cart → saved View pipeline. (5b will add the right-edge Properties↔Cart rail, the Data Link delete-409 dialog, and Properties "Appears in N Views".)

What's in it

  • CartProvider hoisted app-wide (MainLayout, inside PreferencesProvider; removed the route-scoped copy) so the file browser can use the cart.
  • Checkout engine:
    • getOmeZarrChannels(url) — lazy channel list for a dataset.
    • buildViewState(datasets) — merges per-dataset omezarr-helper generated states into one ng_state object + ViewLayerInput[] (decode + concat layers; one dataset's failure is skipped, not fatal).
    • useCartCheckout() — resolves/creates one Data Link per unique (fsp_name, path) (shared datasetKey + normalizeFspRootPath so no duplicate links), builds state, createView.
    • CreateViewButton — consent-gated batch checkout (reuses areDataLinksAutomatic; "don't ask again" toggles the pref). Reused by both entry points.
  • Entry points:
    • Row "Add to Neuroglancer cart" (folders only).
    • Floating selection bar — first consumer of PR 3's checkedFiles: Add N to cart · New View from selection · Clear.
    • Full Layer Cart tab — datasets grouped, expandable to lazy-load + select channels (MT Collapse), Create View + Clear cart. CartContext gained a batch removeManyFromCart.

Notable review catches (fixed on-branch)

  • One broken/stale cart dataset no longer aborts the whole checkout build (per-dataset try/catch).
  • addToCart now awaited + toast.error on failure (was a false-success toast + unhandled rejection).
  • Fixed a stale-closure bug where removing a multi-entry dataset only dropped the last entry (root-caused with a batch removeManyFromCart).
  • Base+channel double-layering: a dataset's base entry is dropped at checkout when specific channels are selected.

Deferred / carry items

  • sharing_mode is a stored label only (not enforced) — per PR 2.
  • Known ceiling: synthesized "Channel N" labels don't name-match generated layers, so buildViewState's channel filter falls back to keep-all (over-inclusive, never drops/crashes); omero-labelled datasets filter correctly. Accepted for read-only-first.
  • Cart-created Data Links don't honor a custom dataLinkSubpathMode prefix (cosmetic; links still work). Follow-up.
  • Channel expansion in the cart tab is disabled for a dataset that has no Data Link yet (no link created just to browse).

Testing

  • Full frontend suite green: 343/343. New tests: getOmeZarrChannels, viewCheckout (incl. skip-on-throw + channel-narrow), useCartCheckout, CreateViewButton, FileBrowserCartItem, SelectionBar, CartTab, CartContext. node-prettier-check + node-eslint-check clean (one pre-existing unrelated lint warning).
  • Note: node-check shows 5 pre-existing type errors in files 5a does not touch (base-branch types mismatch) — reconcile at the stack level.

Built via subagent-driven development from docs/superpowers/plans/2026-08-07-ngviews-05a-cart-pipeline.md.

Wire useCartContext into FileBrowser and add a context-menu item that
adds the right-clicked folder to the Neuroglancer cart, guarded by the
same is_dir && !is_symlink condition the existing folder-only menu
items (Set favorite, Convert to OME-Zarr) already use.

Also add CartProvider to the shared test harness (test-utils.tsx),
matching its real nesting in MainLayout -- FileBrowser is a shared
surface and now depends on CartContext, which the harness didn't
provide, breaking FileTableSelectColumn.test.tsx.
The "Add to Neuroglancer cart" menu item called addToCart without
awaiting it and toasted success unconditionally, so a rejected
preference mutation left an unhandled rejection and a false-positive
success toast. Await it in a try/catch and mirror the sibling
Set favorite item's error-toast pattern.
removeFromCart in a loop closed over the same pre-loop cart snapshot on
every awaited iteration, so removing a multi-entry dataset (base + checked
channels) only persisted the last removal - earlier entries got
reintroduced. Add removeManyFromCart (single filter, single persist) and
use it from CartDatasetRow's remove-all. Also stop a channel-only entry's
label from leaking into the dataset row header when no base entry exists.
Lazily fetch OME-Zarr metadata on first row expand (same trigger as the
existing channel fetch) and render a compact "axis:size" summary next to the
dataset label, so a shape mismatch between cart rows (e.g. different Z
extents) is visible before checkout instead of only after a misaligned View.

Exports getAxesMap from omezarr-helper so CartDatasetRow can map axis name to
its arr.shape index.
CreateViewButton now always opens a dialog with a name FgInput
pre-filled from defaultName before calling checkout, instead of
firing checkout silently when no data-link consent was needed. The
data-link consent copy/switch renders inside the same dialog only
when new links require consent. The create/continue button is
disabled when the trimmed name is empty, and the typed name (not
defaultName) is used for both checkout and the success toast.
@allison-truhlar
allison-truhlar force-pushed the ngviews-05a-cart-pipeline branch from 58d0cdc to 3b704c1 Compare August 12, 2026 19:29
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.

1 participant