Skip to content

feat: run counts and greying out of impossible filter options (#296) - #346

Merged
timdegroot1996 merged 3 commits into
mainfrom
feat/296-cross-filter-availability
Sep 25, 2026
Merged

timdegroot1996 merged 3 commits into
mainfrom
feat/296-cross-filter-availability

Conversation

@timdegroot1996

@timdegroot1996 timdegroot1996 commented Sep 23, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes #296

Problem

The filter dropdowns are built once from the full run data and never recomputed, so they keep offering values that belong to runs another filter has already excluded. With two custom filter dimensions where filter_1=A only ever occurs together with filter_2=C, selecting filter_1=A still offers filter_2=D, which can only ever yield zero runs.

Root cause

setup_custom_filters_in_select_filter_buttons() (and the equivalents for Runs, Run Tags, Versions and Metadata) run once at startup over the whole runs array; filtering itself only happens when the modal closes. Nothing ever tells an option list what the other filters did.

Fix

Every option of the Runs, Run Tags, Versions, Metadata and custom filter dropdowns now shows how many runs remain if that option is the selection of its filter. Options that match nothing are greyed out — they stay visible and selectable, so no value disappears from the modal (the middle ground suggested in the issue).

  • The counts follow the usual faceted-search rule: they are computed with every filter except their own applied, so picking a value never makes the other values of that same filter vanish.
  • The amount filter is left out: "the most recent X runs" is not a category.
  • In NOT mode an option excludes its runs, so its count is what is left over.
  • Both the counts and the greying out can be turned off in Settings → Defaults.

To keep one implementation of the filter logic, the filter functions were split: apply_* functions hold the logic and take their selection as an argument, filter_* functions read the filter modal and call them, and the availability computation reuses the same apply_* functions. Parsed custom_filters and metadata strings are cached, which also removes a per-dimension re-parse from the existing filter pass.

Readability of the dropdowns

Putting counts and greyed-out rows in the dropdowns made it obvious that the panels themselves were hard to read, so a second commit fixes that.

  • The panels had no surface of their own — only position, so the rows inside them painted the background. Those rows use --color-card, which is rgba(30, 41, 59, 0.9) in dark mode, so the modal rows underneath showed through an open dropdown and the text of both was mixed together. The panels now paint an opaque --color-popover-bg with a border, a radius and a shadow, and the rows inside are transparent.
  • The search box scrolled away with its own option list; it is sticky now.
  • Unavailable options were dimmed twice, with colour and opacity: 0.65, which also faded the checkbox and the count — the count being the one thing that explains why a row is greyed out. The opacity is gone (it is ignored on <option> elements in native select popups anyway). What is left is a dedicated --color-text-disabled on the label, a struck-through label and a faint row tint, with the checkbox and the count at full contrast.
  • The counts trailed labels of arbitrary length, so they were impossible to compare. They now sit in their own right-aligned tabular-nums column, which needs them to be a sibling of the label rather than a child: the row is the flex container. Long values are ellipsised instead of pushing the count out of the row.
  • --color-text-muted was darkgrey, ~2.3:1 on the light theme's white, which fails WCAG AA. It is #6c757d (~4.6:1) now. This token is used beyond the filter modal, so light-theme muted text is slightly darker everywhere; no reference screenshot moved.

Tests

  • New tests/javascript/filter_availability.test.js: 14 cases, including the exact matrix from the issue, the exclude-its-own-filter rule, NOT mode, None, date range and suite path. JS suite: 314 passed.
  • Two new robot tests in 06_filters.robot: the counts and greying out, and the two settings that turn them off.
  • Full robot suite in Docker: 105 tests, 105 passed, 0 failed on the first pass (no rerun needed), both before and after the readability commit. Python: 403 passed.

Also in here

Open Filter Dialog now waits for the modal's opening animation to finish. Bootstrap ignores a hide() that arrives while the modal is still animating open, which leaves the modal on screen and makes every later click time out. That race was already flaky on main (the baseline run flaked on 08 Layout); this change shifted the timing enough to hit it repeatedly in 06 Filters.

🤖 Generated with Claude Code

The filter dropdowns were built once from the full run data and never
recomputed, so they kept offering values belonging to runs another
filter had already excluded: selecting filter_1=A still offered
filter_2=D even though no run has that combination.

Every option of the Runs, Run Tags, Versions, Metadata and custom
filters now shows how many runs remain if that option is the selection
of its filter, and options that match nothing are greyed out. They stay
visible and selectable, so no value ever disappears from the modal.

The counts follow the usual faceted-search rule: they are computed with
every filter except their own applied, so picking a value never makes
the other values of that same filter vanish. The amount filter is left
out, as "the most recent X runs" is not a category. In NOT mode an
option excludes its runs, so its count is what is left over.

To keep one implementation of the filter logic, the filter functions
were split: the apply_* functions hold the logic and take their
selection as an argument, the filter_* functions read the filter modal
and call them, and the availability computation reuses the same apply_*
functions. Parsed custom_filters and metadata strings are cached, which
also removes a per-dimension re-parse from the existing filter pass.

Both the counts and the greying out can be turned off in the settings.

Open Filter Dialog now waits for the modal's opening animation to
finish: Bootstrap ignores a hide() that arrives while the modal is
still animating open, which leaves the modal on screen and makes every
later click time out. That race was already flaky on main and this
change shifted the timing enough to hit it repeatedly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The dropdown panels were unreadable, most of all with the new greying out
of unavailable options.

The panels had no surface of their own: only position, so the rows inside
them painted the background. Those rows use --color-card, which is
rgba(30, 41, 59, 0.9) in dark mode, so the modal rows underneath showed
through the open dropdown and the text of both was mixed together. The
panels now paint an opaque --color-popover-bg with a border, a radius and
a shadow, and the rows inside are transparent. The search box at the top
of a panel scrolls with its option list, so it is sticky now.

Unavailable options were dimmed with colour *and* opacity: 0.65, which
also faded the checkbox and the count - the count being the one thing
that explains why the row is greyed out. The opacity is gone (it is
ignored on <option> elements in native select popups anyway). What is
left is a dedicated --color-text-disabled on the label, a struck-through
label and a faint row tint, with the checkbox and the count at full
contrast.

The counts trailed labels of arbitrary length, so they were impossible to
compare. They now sit in their own right-aligned tabular-nums column,
which needs them to be a sibling of the label rather than a child: the
row is the flex container. Long values are ellipsised instead of pushing
the count out of the row.

Finally --color-text-muted was darkgrey, which is ~2.3:1 on the light
theme's white and fails WCAG AA; it is #6c757d (~4.6:1) now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@timdegroot1996
timdegroot1996 marked this pull request as ready for review September 24, 2026 23:12
Resolves the conflicts with the per page hidden custom filters (#349):

- settings.js and the eventlisteners.js import list are a union of both sides
- Open Filter Dialog keeps this branch's wait, which also checks the Bootstrap
  transition state instead of only the opacity; Open Settings Tab is upgraded
  to the same wait
- 06_filters.robot keeps both appended tests

Also fixes an interaction that merged clean but was wrong. The availability
model applied every custom filter dimension of the current selection, while
the real pipeline skips the ones hidden on the active page, so the run counts
and the greying out were narrowed by a filter that is not applied to the data.
normalize_filter_selections now leaves the hidden dimensions out, which covers
both apply_filters_except and compute_filter_option_availability, and the
hidden per page test asserts the counts on a page where a dimension is hidden.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@timdegroot1996
timdegroot1996 merged commit bd2fdb9 into main Sep 25, 2026
3 checks passed
timdegroot1996 added a commit that referenced this pull request Sep 25, 2026
…reset

Resolves the conflicts with the filter option availability (#346) and the per
page hidden custom filters (#349):

- README and the metadata tooltip keep both descriptions, the amount tooltip
  keeps this branch's per project rewrite
- the menu.js and overview.js import lists are a union of both sides
- filter.test.js keeps both appended suites

The availability counts are unaffected by the per project amount: #346 leaves
the amount filter out of them on purpose, since it is not a category.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@timdegroot1996 timdegroot1996 mentioned this pull request Sep 26, 2026
@timdegroot1996
timdegroot1996 deleted the feat/296-cross-filter-availability branch September 26, 2026 15:58
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.

[Improvement] Custom filter does not apply to options of another custom filters

1 participant