UXE-685: Migrate VariantHistory page to Via - #1925
Conversation
| {taskNamesForBuildVariant?.map((taskName) => ( | ||
| <ComboboxOption key={taskName} value={taskName} /> | ||
| {(taskNamesForBuildVariant ?? []).map((taskName) => ( | ||
| <ComboboxItem key={taskName} id={taskName}> |
There was a problem hiding this comment.
There was a problem hiding this comment.
This is kind of interesting. The LG combobox did have an dropdownWidthBasis prop that could be set to option or trigger. option would have made the width grow to the size of the largest option. However, trigger was the default and this prop was never actually set in Spruce. So before this change I believe that both the trigger and the options would have always been set to 300px I believe. If I'm missing something though and this isn't true, definitely let me know please!
Unfortunately dropdownWidthBasis is no longer a prop in Via. We could probably set some sort of max width in CSS, maybe? But I do think this is how it rendered previously if I'm no mistaken.
There was a problem hiding this comment.
Interesting, that seems true but I guess the wrap worked better in LG (live here)

Giving some more width to the component makes sense though! And should the dropdown items handle wrap better, or maybe we could apply some word break css?
There was a problem hiding this comment.
Oh, that's a really good callout on the wrapping! Yes! I think maybe it should. Let me look into this on the Via side. Will update here with what I find.
There was a problem hiding this comment.
I've added a ticket to fix this in Via https://jira.mongodb.org/browse/UXE-994. If it doesn't get in before this merge, I'll make sure to bump the version here once it's published
| <div className={styles.container}> | ||
| <LabelCellContainer> | ||
| <ListSkeleton /> | ||
| <Skeleton isLoading> |
There was a problem hiding this comment.
I feel like having isLoading always true is a bit of an antipattern; shouldn't this value be used to toggle its visibility?
There was a problem hiding this comment.
I think it depends on how the component gets used. For Via's Skeleton, isLoading has to be true for the shimmer to apply, so when it's wrapping real content that will eventually load, you'd tie it to that loading state.
Here LoadingRow is only ever placeholder lines, there's nothing real to toggle to. The loading logic lives a level up in HistoryTable and this only mounts while loading is true.
If there was something we could wrap, we could drop LoadingSection altogether and wrap the real rows in <Skeleton isLoading={loading}>, but I don't think that's possible. I think that's why we have the arbitrary placeholder. Please correct me if I'm wrong!
Replace the LG TextInput wrapper in HistoryTableTestSearch with Via SearchField so both header inputs share Via's label typography, 32px height and border tokens. ComboboxItem needs an explicit textValue: Via runs children through composeRenderProps to append the checkmark, so RAC cannot infer textValue from the string child and every chip rendered empty. Move FilterChips under the search input it belongs to. Offset is 8px to match the combobox, whose chips clear the input by the Field gap (4px) plus comboBoxChipGroup margin (4px). Page width moves to searchColumn so the shared component no longer dictates its own page geometry.
Reverts the header-column placement only. FilterChips relies on wrapping behavior it gets from the full-width row; constraining it to a 40% column loses that. Chip placement goes to design before any further change.
|
@sophstad This is mostly ready for another look. Waiting on input regarding the page design, but should be good from a code feedback standpoint! |
|
|
||
| return ( | ||
| <RowContainer> | ||
| <div className={styles.rowContainer}> |
There was a problem hiding this comment.
[nit] I noticed Field in the Via Storybook, is this something worth using here?
There was a problem hiding this comment.
Field is technically marked @internal and I don't think is exported from the package root. This is confusing because it's in the storybook, sorry about that! We're working on fixing up the Storybook as we speak 🙂
That said, I don't believe it would actually apply here. It's really meant to wrap an input that uses React Aria Components under the hood.
| {taskNamesForBuildVariant?.map((taskName) => ( | ||
| <ComboboxOption key={taskName} value={taskName} /> | ||
| {(taskNamesForBuildVariant ?? []).map((taskName) => ( | ||
| <ComboboxItem key={taskName} id={taskName}> |
There was a problem hiding this comment.
Interesting, that seems true but I guess the wrap worked better in LG (live here)

Giving some more width to the component makes sense though! And should the dropdown items handle wrap better, or maybe we could apply some word break css?
| !inactive && (!!loadingTestResults || failingTests.length > 0); | ||
|
|
||
| return ( | ||
| <TooltipRoot align="center" isDisabled={!showTooltip} side="right"> |
There was a problem hiding this comment.
The tooltip show animation is kinda flickery when looking at a tooltip on Firefox, are you able to reproduce this?
There was a problem hiding this comment.
I don't think I'm seeing this! Any chance you could take a short screen recording to capture what you're seeing on your end?
| @@ -38,22 +38,26 @@ const ColumnPaginationButtons: React.FC<ColumnPaginationButtonProps> = ({ | |||
| return ( | |||
| <div className={styles.container}> | |||
There was a problem hiding this comment.
Optional but moving the pagination buttons inline with the other input elements seems reasonable to me
There was a problem hiding this comment.
Makes sense. I'll update this with the redesign!
There was a problem hiding this comment.
@sophstad I tried this but it caused some weird UI in smaller browser. I chose to just leave it as is, but let me know if you want anything adjusted!
| @@ -91,13 +91,8 @@ const ColumnHeaders: React.FC<ColumnHeadersProps> = ({ | |||
| // eslint-disable-next-line react/no-array-index-key | |||
| <LoadingCell key={`loading_cell_${i}`} isHeader /> | |||
There was a problem hiding this comment.
Do we actually need to use loaders here? If task names are selected we should know the number of columns without waiting for any data, and if not maybe we could just keep things simple and omit? This is just being nitpicky/interested in details, though, feel free to ignore 😝
There was a problem hiding this comment.
That's a good call out. columnLimit is just DEFAULT_COLUMN_LIMIT rather than the actual selected column count, so the skeletons can overshoot what ends up rendering.
I'm inclined to leave it here though, since this block is untouched by the migration and BaseRow falls back to columnLimit the same way. Changing just the header would desync the two. Totally your call though if you want to remove them!
Chips pushed the table down as tasks were selected. showChips={false} drops the chip row; Via 0.8.6 replaces it with a selection count in the closed field (UXE-839, via#594), which lands regardless of showChips.
Bump needs tokens 0.3.4 alongside components 0.8.6. Carries two visual changes beyond this page: focus-ring offset (0.8.4) and the text.link contrast fix, so Chromatic drift outside variantHistory is expected.
TaskSelector test asserted a chip; now asserts the count summary and the URL round-trip.
# Conflicts: # apps/parsley/package.json # apps/spruce/package.json # apps/spruce/src/components/HistoryTable/ColumnPaginationButtons.tsx # pnpm-lock.yaml
|
@sophstad This should be ready for another look. I've updated the screenshots in the description to represent the new page states |
# Conflicts: # apps/parsley/package.json # apps/spruce/package.json # packages/lib/package.json # pnpm-lock.yaml
Via's Combobox renders role=combobox, not role=textbox, so the Tasks locator never resolved. Via tooltips are React Aria based and ignore hover until a pointer event establishes pointer modality, so a bare .hover() on a fresh page never opened them - same reason the unit test already calls primePointerModality(). Verified both against the real Storybook DOM: new locator resolves (old resolves to 0), hoverForTooltip opens the tooltip (bare .hover() does not).
| trigger={ | ||
| <Body onClick={onClick} weight="medium"> | ||
| <TooltipRoot align="center" side="top"> | ||
| <TooltipTrigger> |
There was a problem hiding this comment.
Are we sure that task has failed tests attached to it?
I'm having a hard time replicating this, and I could be missing something, but the logic that enables the tooltip is the same on this branch as it is on main:
- main:
enabled={!inactive && (loadingTestResults || failingTests.length > 0)} - branch:
isDisabled={!(!inactive && (!!loadingTestResults || failingTests.length > 0))}
Same inputs, same result, so anything that shows a tooltip on main should show one here too.
The tooltip itself does render. I can see it in this branch's published Storybook. That story hardcodes failingTests though, so it only proves the component works, not the data path.
For the data path I think staging is the better comparison since it's running main. I don't get tooltips there either: https://spruce-staging.corp.mongodb.com/variant-history/zackary-bisect/s3put-public-read. None of those failed tasks have failed tests attached to them. Same thing locally. So the tooltip is correctly disabled.
There was a problem hiding this comment.
wow i'm really sorry, i looked at a couple tasks that just happened to not have failing tests 😭 this does seem to be working correctly!
| trigger={ | ||
| <Body onClick={onClick} weight="medium"> | ||
| <TooltipRoot align="center" side="top"> | ||
| <TooltipTrigger> |
There was a problem hiding this comment.
wow i'm really sorry, i looked at a couple tasks that just happened to not have failing tests 😭 this does seem to be working correctly!


https://jira.mongodb.org/browse/UXE-685
Summary
Screenshots
No Filters
Before
After
With Filters
Before
After
Loading
Before
After
Testing