Skip to content

feat(dashboards): collections create/edit UI#1100

Draft
fhennig wants to merge 14 commits intogeneralized-collections-ui-detail-viewfrom
generalized-collections-ui-edit-view
Draft

feat(dashboards): collections create/edit UI#1100
fhennig wants to merge 14 commits intogeneralized-collections-ui-detail-viewfrom
generalized-collections-ui-edit-view

Conversation

@fhennig
Copy link
Copy Markdown
Contributor

@fhennig fhennig commented Mar 23, 2026

Summary

Adds create and edit UI for collections. It's the same form in both cases.

TODO - more description.

When hitting on 'save' you get to the 'view collection' page, which doesn't exist yet in this PR - it's implemented here: #1099 (I used to have this PR based on the other one, but eventually though it's simpler to keep them independent)

Screenshot

New collection button on the overview page:

image **General overview** image

PR Checklist

  • All necessary documentation has been adapted.
  • The implemented feature is covered by an appropriate test.

@vercel
Copy link
Copy Markdown

vercel bot commented Mar 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dashboards Ready Ready Preview, Comment Mar 26, 2026 1:32pm

Request Review

@fhennig fhennig changed the title Generalized collections UI edit view feat(dashboards): collections create/edit UI Mar 23, 2026
@fhennig fhennig force-pushed the generalized-collections-ui-detail-view branch 3 times, most recently from c560f43 to 4adeee1 Compare March 24, 2026 09:43
@fhennig fhennig force-pushed the generalized-collections-ui-edit-view branch from ebd3666 to 4daffe2 Compare March 24, 2026 16:40
only on staging for now, remove when enabling on prod: #1108

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
fhennig and others added 10 commits March 26, 2026 11:10
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reads lineageFields from the per-organism LAPIS config and renders a
GsLineageFilter for each field above the mutation filter. Values are
stored as plain strings in filterObject. Also fixes the type toggle
discriminator ('mutationList' → 'filterObject') and adds the showLabel
prop to GsMutationFilter.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move mutation filter to top with label re-enabled, lineage filters
below. Replace radio type toggle with a checkbox at the bottom.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e/description changes

The variant editor contains GsMutationFilter and GsLineageFilter — web components
from @genspectrum/dashboard-components that are expensive to render. Previously,
typing in the variant name or description field caused these components to re-render
on every keystroke, resulting in noticeable input lag.

Root cause: React re-renders the entire component subtree whenever a parent
re-renders. Typing a name called setVariants in CollectionForm, which re-rendered
all VariantEditors, which re-rendered MutationListVariantFields, which re-rendered
the Gs* web components — even though none of their data had changed.

Fix applied in layers:

1. CollectionForm: wrapped addVariant, updateVariant, removeVariant in useCallback
   so their references are stable across re-renders.

2. VariantEditor: wrapped in memo so it only re-renders when its own props change,
   not when unrelated CollectionForm state (e.g. collection name) changes. The
   onChange/onRemove props are now stable thanks to (1), so memo's shallow
   comparison holds.

3. MutationListVariantFields: wrapped in memo and refactored to receive filterObject
   directly instead of the full variant object. This means its props only change
   when filter data changes — not when name or description changes.

4. handleFilterObjectChange: the onChange handler passed to MutationListVariantFields
   needs to build a full VariantUpdate including name and description. If we put
   variant in useCallback's deps, the callback is recreated on every name/description
   change, breaking memo. Instead, we store variant in a ref (variantRef.current =
   variant on every render) and read from it inside the callback. The ref is always
   current without being a dependency, so the callback is stable for the lifetime
   of the component.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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