FEAT: Pick an operation from existing values in the labels bar - #2396
Open
varunj-msft wants to merge 9 commits into
Open
FEAT: Pick an operation from existing values in the labels bar#2396varunj-msft wants to merge 9 commits into
varunj-msft wants to merge 9 commits into
Conversation
Setting the operation label meant retyping the name from memory. The suggestion list that was supposed to help never appeared, because it filtered the known values against the value being replaced -- with the shipped default op_trash_panda that matches nothing. Editing the operation label now opens a combobox listing the operations already in memory, sourced from the labels request the bar already makes. Typing filters the list and offers to create a name that doesn't exist yet. - Existing values are selectable as-is; only new names are validated, so operations created before the current naming rules stay usable. - The editor now renders in the labels popover too. Clicking a label there previously set edit state but rendered no editor, which showed nothing at all when the chip was too narrow to fit inline. - Label rows are reachable by keyboard, and focus moves into the picker. - Escape, clicking away, and Tab all leave without writing a value. The selected operation applies to attacks started afterwards; it does not relabel existing ones.
Contributor
|
Screenshots please! Or video. |
The dropdown took its width from the input it hangs off, so longer operation names were cut off mid-name with no ellipsis -- op_2026_05_mai_image_2.5 rendered as op_2026_05_mai_image. Names never wrap out of it either: values may only contain letters, digits and underscores, none of which are line break opportunities. Widening the input instead would push it past the labels bar and clip the control itself, so leave the input alone and let the dropdown size to its own content.
Rejecting a bad name after the fact put the reason in a line of text beside the picker, and the labels bar clips anything that overflows it. On a narrow ribbon none of it survived; at full width it read "Only l". The message also stayed on screen while the name was corrected. The rules are now stated in the dropdown as the name is typed, and a name that breaks them is not offered for creation at all. The dropdown sizes to its contents, so the whole message is always readable. Fluent dims disabled options to roughly 1.9:1 against their background, which is too faint for text that has to be read rather than chosen, so the notes carry their own colour.
With more operations than fit under the input -- and there are already around sixty in use -- the list stopped hanging off the picker and became a full height column pinned to the top of the window, covering the page. Giving it a ceiling lets it stay where it belongs and scroll instead. A name typed into the picker also disappeared from it. Operations are read once from the labels API, and a name only reaches that API after an attack has been stored under it, so a name created moments earlier was absent when the picker was reopened and was offered for creation again. Newly created names now join the list they came from.
A failed labels request left the picker looking like a working picker with nothing in it, so someone whose backend had hiccuped was told their operations did not exist and invited to type a name that already existed somewhere else. It now says it could not load them, and keeps the "none recorded yet" wording for the case where that is actually true. Also fold the operation naming rules back into the single validator they were copied from, and stop the newly created name from being appended to a list captured before the request that fills it had returned.
The picker lets a name be typed and created before the request that fills it has come back, and the response then replaced everything that had been collected in the meantime, so a name created during those first moments disappeared again as soon as the list arrived. The response is now merged with what is already there rather than replacing it.
The 240px cap never took effect. Fluent's combobox defaults to autoSize: true, which writes its own max-height inline once positioned, and an inline style beats the class the cap lives in. Overriding only matchTargetSize left autoSize in place, so the list stretched to whatever room it had: 501px below the input at an 800px viewport, and above the input it ran to the top of the window. Asking Fluent to auto-size width alone leaves the height to the class. Measured in Chromium with 60 options: 240px and anchored under the input at 800px, 240px and anchored above it at 500px and 420px, still scrolling internally, and the dropdown width is unchanged. It shrinks below the cap when there are fewer options. No test: jsdom does not position the popup, so the inline max-height that caused this is never written there and a unit assertion would pass either way.
Sizing the dropdown to width alone hands the height back to the class, which is what makes the 240px cap work, but it also gives up Fluent's vertical fitting. The cap was a flat 240px, so in a window shorter than about 250px the list ran past the viewport edge and the options there were unreachable. Yielding to the viewport keeps both: measured with 60 options, the list is still the full 240px and anchored at every height from 300px up, and at 200px it now renders 168px and stays on screen instead of overflowing by 40px.
Every sizing bug in this feature shipped past a green unit run, because jsdom has no layout engine: reverting the fix that caps the list height leaves all 53 LabelsBar unit tests passing. These run in the existing mock Playwright project, which CI already runs on every PR and which needs only Vite. They assert what jsdom cannot -- the list is capped and anchored to the input, it stays on screen when it opens upwards, and a long operation name is not cut off. Reverting the cap fails the first one with a 501px list.
Contributor
Yes, would be great if it persisted! Same for operator name. I suppose that one persists in the deployed version due to auth but in the local one it doesn't. |
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.
Description
Setting the
operationlabel meant retyping the name from memory. There was a suggestion list meant to help, but it never appeared: it filtered the known values against the value you were replacing, and with the shipped defaultop_trash_pandathat matches nothing.Clicking the
operationlabel now opens a combobox listing the operations already in memory, using the labels request the bar was already making. Typing filters the list, and offers to create a name that doesn't exist yet.A few details worth calling out:
some-op-name) stay usable.The operation you pick applies to attacks you start afterwards; it doesn't relabel existing ones. It also isn't persisted across a page refresh — that's a separate question about where per-user GUI state should live, so I left it out rather than guess.
No backend or API changes.
Tests and Documentation
21 new tests in
LabelsBar.test.tsxcovering the picker: options listed on open without clearing the field, filtering, creating a new name, rejecting an invalid one, selecting a legacy value that predates the naming rules, loading and empty states, keyboard select/dismiss, and editing from the popover. Existing label behavior is unchanged and still covered.npx jest src/components/Labels src/components/Home src/App.test.tsx→ 113 passingnpm run lintandnpm run type-check→ cleanLabelsBar.tsxgoes up (branches 82.65 → 85.81, lines 89.65 → 92.85)Docs: added a short paragraph to
doc/gui/0_gui.mddescribing the picker and the "applies to new attacks only" behavior. It's a plain markdown page with no paired notebook, so JupyText doesn't apply here.