Skip to content

fix(workspace-cleanup): make the Filters panel scrollable - #14629

Merged
brennanb2025 merged 2 commits into
mainfrom
brennanb2025/cleanup-filter-popover-scroll
Aug 15, 2026
Merged

brennanb2025 merged 2 commits into
mainfrom
brennanb2025/cleanup-filter-popover-scroll

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

ELI5

The filter panel in the workspace cleanup dialog was too tall for its box and could not be scrolled, so the bottom filters were stuck behind the footer. This makes the filter list scroll while keeping the footer visible, including in short windows.

What Changed

  • Bound the Filters popover to the smaller of its normal 471px height and Radix's available popover height.
  • Made the facet ScrollArea the shrinking min-h-0 flex-1 body of the popover.
  • Kept the result/footer row as a separate fixed flex item.
  • Added a focused regression test for the bounded popover and scroll-body layout.

Why

The old ScrollArea Root had only max-height while its Radix viewport used h-full. Without a definite height, the viewport expanded to the full facet content, so the Root clipped the panel instead of providing a scrollable region.

Giving the popover a definite, available-height-aware flex layout lets the facet body shrink and scroll. The 471px normal cap preserves the previous 420px facet area plus its footer, while short windows reduce the scroll body instead of clipping the footer.

Linked Issue

Fixes #14628

Visual Proof

BEFORE — panel clipped at the cap, no scrollbar; ARCHIVED collides with the footer and its controls are unreachable:

filters panel clipped, Archived unreachable

AFTER — exact-head Electron screenshots are attached in the QA comment below, covering normal height, a 500px-tall renderer, and the final controls after scrolling.

Testing

Verified locally on macOS:

  • Focused filter-bar Vitest: 2 passed.

  • pnpm run typecheck clean.

  • Direct oxlint, formatting, React Doctor changed-lines, and git diff --check clean.

  • Electron/CDP on exact HEAD 583166d0b29b8f4f4ca37d2a963323fcd2dd9ecf:

    • Normal height: 420px viewport with 2090px scrollable content; footer visible.
    • 500px renderer height: scroll body shrank to 312px; footer remained fully visible.
    • Scrolled to and clicked the final Safety control without footer overlap.
  • Manually tested in the rendered Electron app

  • Automated regression test added

Review

  • Security: no new IPC, data flow, dependency, or permission change.
  • Cross-platform (Linux/Windows/macOS): Chromium CSS/layout only; no paths, shells, shortcuts, or platform branches.
  • Remote SSH: renderer-local chrome only; no scan, transport, or host-state change.
  • Mobile: no mobile-facing surface touched; this dialog is desktop-only.
  • Backwards compatibility: no persisted state, schema, IPC, RPC, or wire contract.
  • Performance: neutral; no new work, renders, polling, listeners, or allocations.

Checklist

Author

  • X / Twitter: @BrennanKB5

The height cap sat on the ScrollArea Root, but the Radix viewport inside is
h-full — under an indefinite root height that collapses to auto, so the
viewport grew to full content height with nothing to scroll while the root
clipped at 420px. The last facet groups (Archived, and the tail of Workspace
status) were unreachable behind the footer.

Move the cap to the viewport, which is what the ScrollArea wrapper's
viewportClassName exists for. Adds a regression test that pins the cap to the
viewport; it fails against the previous markup.
@coderabbitai

coderabbitai Bot commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d13e5a3e-0e5d-4d79-a39a-f7db016a8150

📥 Commits

Reviewing files that changed from the base of the PR and between 3a21258 and 583166d.

📒 Files selected for processing (2)
  • src/renderer/src/components/workspace-cleanup/workspace-cleanup-filter-bar.test.tsx
  • src/renderer/src/components/workspace-cleanup/workspace-cleanup-filter-bar.tsx

📝 Walkthrough

Walkthrough

Updated the workspace cleanup filter popover to use a capped flex-column layout. The facet list now fills the available space and scrolls without hiding the footer. Added a shared test renderer and assertions for the open popover height and scroll-area layout classes.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes directly address issue #14628 by making the capped Filters panel scrollable and restoring access to all filter groups.
Out of Scope Changes check ✅ Passed The changes are limited to the workspace cleanup filter layout and its regression test, with no unrelated code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed The title clearly and concisely describes the main change: making the Workspace Cleanup Filters panel scrollable.
Description check ✅ Passed The description covers the change, cause, issue, visual proof, testing, compatibility review, and checklist; only the AI Disclosure section is omitted.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Electron QA on 583166d0b29b8f4f4ca37d2a963323fcd2dd9ecf (isolated ORCA_DEV_USER_DATA_PATH, CDP 9336). Identity: pr-14629-filters-scroll @ brennanb2025/cleanup-filter-popover-scroll.

Exercised Resource Manager → Clean up workspaces → Filters.

  • Normal height (999px): facet viewport 420px / 2090px content, scrollbar present; footer Showing 0 of 0 + Clear filters stays pinned.
  • ~500px renderer height: popover shrinks to 363px; footer remains fully visible.
  • Scrolled to the last Safety controls and clicked Only workspaces I can delete now (badge 1). Footer stayed visible and did not cover the control.

No filter/popover/scroll errors in renderer console or app logs. Desktop-only pass; no product changes, no merge.

Normal height — scroll body + fixed footer
01-filters-normal-height.png

~500px — footer still visible
02-filters-500px-footer-visible.png

~500px scrolled to last controls (clicked)
03-filters-500px-scrolled-to-last-controls.png

@brennanb2025
brennanb2025 merged commit 83d79f3 into main Aug 15, 2026
44 checks passed
brennanb2025 added a commit that referenced this pull request Aug 23, 2026
…every filter patch

A profile carried `activity.idleMinDays = 20` that the user never set, hiding 253
of 799 workspaces on open. Chromium mutates a *focused* number input on every wheel
tick, and before #14629 the facet panel could not scroll, so the natural response --
cursor into the panel, spin the wheel -- walked the threshold up and persisted it.

Two fixes:

- `FacetNumberField` renders `type="text" inputMode="numeric"`. A wheel cannot
  mutate a text input, and the parser already takes strings. `preventDefault` on a
  focused number input would also work, but it blocks the wheel's default action --
  which includes scrolling the nearest scrollable ancestor -- and would re-break the
  panel scrolling #14629 just fixed, in exactly the reported gesture. All five
  numeric facets share this one field.
- `patchFilters` closed over the render's `browse` snapshot, so two patches in one
  tick dropped one. It now writes through a functional update against the latest
  store state. `toggleSortField` and `clearFilters` had the same defect.

Both tests were confirmed to fail against the unfixed source before being kept.
brennanb2025 added a commit that referenced this pull request Aug 24, 2026
…every filter patch (#15298)

A profile carried `activity.idleMinDays = 20` that the user never set, hiding 253
of 799 workspaces on open. Chromium mutates a *focused* number input on every wheel
tick, and before #14629 the facet panel could not scroll, so the natural response --
cursor into the panel, spin the wheel -- walked the threshold up and persisted it.

Two fixes:

- `FacetNumberField` renders `type="text" inputMode="numeric"`. A wheel cannot
  mutate a text input, and the parser already takes strings. `preventDefault` on a
  focused number input would also work, but it blocks the wheel's default action --
  which includes scrolling the nearest scrollable ancestor -- and would re-break the
  panel scrolling #14629 just fixed, in exactly the reported gesture. All five
  numeric facets share this one field.
- `patchFilters` closed over the render's `browse` snapshot, so two patches in one
  tick dropped one. It now writes through a functional update against the latest
  store state. `toggleSortField` and `clearFilters` had the same defect.

Both tests were confirmed to fail against the unfixed source before being kept.
brennanb2025 added a commit that referenced this pull request Aug 24, 2026
…e content (#16206)

* fix(popover): wheel-scroll a popover whose scroller is nested, not the content

The workspace-cleanup Filters panel cannot be scrolled with a wheel. Only the
scrollbar drag and focus-scroll work. Two independent Electron QA passes measured
it on main: wheel events over that popover arrive defaultPrevented, panel
scrollTop 0 -> 0, while the candidate list inside the dialog subtree scrolls
normally.

Cause: the popover portals outside the Radix dialog subtree, so
react-remove-scroll's scroll-lock cancels wheel there. #14629 added a shim for
exactly this, but it scrolls `event.currentTarget` -- the PopoverContent -- and
only when that element is itself overflowing. The Filters panel is a flex column
holding a ScrollArea above a pinned footer, so PopoverContent is overflow-hidden
and the real scroller is a descendant. The shim looked at the wrong element and
returned early.

The shim now resolves the nearest scrollable element between the wheel target and
the content, inclusive of both, so it handles the nested-viewport shape as well as
the flat one. Still opt-in via `popover-scroll-content`; popovers without the
class are untouched. The cleanup Filters panel opts in.

This is the unfixed half of the original report. #14629 fixed the panel being
clipped; the wheel -- what you actually reach for -- stayed dead.

The nested test fails against the shipped shim and the other two stay green, so it
reproduces the bug without redefining existing behaviour.

* fix(popover): split the wheel-shim opt-in from the scroll-container styling

Two fixes on top of the reviewer's round.

**The reviewer's change, kept.** `resolvePopoverScroller` no longer falls back to
the content element unconditionally; it must match the overflow test like any
other candidate. The reviewer flagged that this could break the existing opted-in
popovers, so I checked: `.popover-scroll-content` sets `overflow-y: auto`
(main.css:601-607), so every one of them still resolves. The test needs an inline
style only because happy-dom does not apply the stylesheet -- noted in the test so
nobody reads it as a production concern.

**A bug of mine the review did not reach.** Opting the cleanup Filters panel in via
`popover-scroll-content` would also have applied that class's
`max-height: min(15rem, ...)`, crushing the panel's 471px flex column to 240px.
The class conflates 'style me as a scroll container' with 'run the wheel shim', and
a popover that manages its own layout needs only the second.

So the shim now accepts `popover-wheel-scroll` as a styling-free marker, and the
Filters panel uses that. `popover-scroll-content` keeps implying it, so no existing
caller changes.
paidaxingyo666 pushed a commit to paidaxingyo666/Manta that referenced this pull request Aug 25, 2026
…every filter patch (stablyai#15298)

A profile carried `activity.idleMinDays = 20` that the user never set, hiding 253
of 799 workspaces on open. Chromium mutates a *focused* number input on every wheel
tick, and before stablyai#14629 the facet panel could not scroll, so the natural response --
cursor into the panel, spin the wheel -- walked the threshold up and persisted it.

Two fixes:

- `FacetNumberField` renders `type="text" inputMode="numeric"`. A wheel cannot
  mutate a text input, and the parser already takes strings. `preventDefault` on a
  focused number input would also work, but it blocks the wheel's default action --
  which includes scrolling the nearest scrollable ancestor -- and would re-break the
  panel scrolling stablyai#14629 just fixed, in exactly the reported gesture. All five
  numeric facets share this one field.
- `patchFilters` closed over the render's `browse` snapshot, so two patches in one
  tick dropped one. It now writes through a functional update against the latest
  store state. `toggleSortField` and `clearFilters` had the same defect.

Both tests were confirmed to fail against the unfixed source before being kept.

(cherry picked from commit 4bc9e6b)
paidaxingyo666 pushed a commit to paidaxingyo666/Manta that referenced this pull request Aug 25, 2026
…e content (stablyai#16206)

* fix(popover): wheel-scroll a popover whose scroller is nested, not the content

The workspace-cleanup Filters panel cannot be scrolled with a wheel. Only the
scrollbar drag and focus-scroll work. Two independent Electron QA passes measured
it on main: wheel events over that popover arrive defaultPrevented, panel
scrollTop 0 -> 0, while the candidate list inside the dialog subtree scrolls
normally.

Cause: the popover portals outside the Radix dialog subtree, so
react-remove-scroll's scroll-lock cancels wheel there. stablyai#14629 added a shim for
exactly this, but it scrolls `event.currentTarget` -- the PopoverContent -- and
only when that element is itself overflowing. The Filters panel is a flex column
holding a ScrollArea above a pinned footer, so PopoverContent is overflow-hidden
and the real scroller is a descendant. The shim looked at the wrong element and
returned early.

The shim now resolves the nearest scrollable element between the wheel target and
the content, inclusive of both, so it handles the nested-viewport shape as well as
the flat one. Still opt-in via `popover-scroll-content`; popovers without the
class are untouched. The cleanup Filters panel opts in.

This is the unfixed half of the original report. stablyai#14629 fixed the panel being
clipped; the wheel -- what you actually reach for -- stayed dead.

The nested test fails against the shipped shim and the other two stay green, so it
reproduces the bug without redefining existing behaviour.

* fix(popover): split the wheel-shim opt-in from the scroll-container styling

Two fixes on top of the reviewer's round.

**The reviewer's change, kept.** `resolvePopoverScroller` no longer falls back to
the content element unconditionally; it must match the overflow test like any
other candidate. The reviewer flagged that this could break the existing opted-in
popovers, so I checked: `.popover-scroll-content` sets `overflow-y: auto`
(main.css:601-607), so every one of them still resolves. The test needs an inline
style only because happy-dom does not apply the stylesheet -- noted in the test so
nobody reads it as a production concern.

**A bug of mine the review did not reach.** Opting the cleanup Filters panel in via
`popover-scroll-content` would also have applied that class's
`max-height: min(15rem, ...)`, crushing the panel's 471px flex column to 240px.
The class conflates 'style me as a scroll container' with 'run the wheel shim', and
a popover that manages its own layout needs only the second.

So the shim now accepts `popover-wheel-scroll` as a styling-free marker, and the
Filters panel uses that. `popover-scroll-content` keeps implying it, so no existing
caller changes.

(cherry picked from commit b085e67)
dallascrilley pushed a commit to dallascrilley/orca that referenced this pull request Aug 27, 2026
…every filter patch (stablyai#15298)

A profile carried `activity.idleMinDays = 20` that the user never set, hiding 253
of 799 workspaces on open. Chromium mutates a *focused* number input on every wheel
tick, and before stablyai#14629 the facet panel could not scroll, so the natural response --
cursor into the panel, spin the wheel -- walked the threshold up and persisted it.

Two fixes:

- `FacetNumberField` renders `type="text" inputMode="numeric"`. A wheel cannot
  mutate a text input, and the parser already takes strings. `preventDefault` on a
  focused number input would also work, but it blocks the wheel's default action --
  which includes scrolling the nearest scrollable ancestor -- and would re-break the
  panel scrolling stablyai#14629 just fixed, in exactly the reported gesture. All five
  numeric facets share this one field.
- `patchFilters` closed over the render's `browse` snapshot, so two patches in one
  tick dropped one. It now writes through a functional update against the latest
  store state. `toggleSortField` and `clearFilters` had the same defect.

Both tests were confirmed to fail against the unfixed source before being kept.
dallascrilley pushed a commit to dallascrilley/orca that referenced this pull request Aug 27, 2026
…e content (stablyai#16206)

* fix(popover): wheel-scroll a popover whose scroller is nested, not the content

The workspace-cleanup Filters panel cannot be scrolled with a wheel. Only the
scrollbar drag and focus-scroll work. Two independent Electron QA passes measured
it on main: wheel events over that popover arrive defaultPrevented, panel
scrollTop 0 -> 0, while the candidate list inside the dialog subtree scrolls
normally.

Cause: the popover portals outside the Radix dialog subtree, so
react-remove-scroll's scroll-lock cancels wheel there. stablyai#14629 added a shim for
exactly this, but it scrolls `event.currentTarget` -- the PopoverContent -- and
only when that element is itself overflowing. The Filters panel is a flex column
holding a ScrollArea above a pinned footer, so PopoverContent is overflow-hidden
and the real scroller is a descendant. The shim looked at the wrong element and
returned early.

The shim now resolves the nearest scrollable element between the wheel target and
the content, inclusive of both, so it handles the nested-viewport shape as well as
the flat one. Still opt-in via `popover-scroll-content`; popovers without the
class are untouched. The cleanup Filters panel opts in.

This is the unfixed half of the original report. stablyai#14629 fixed the panel being
clipped; the wheel -- what you actually reach for -- stayed dead.

The nested test fails against the shipped shim and the other two stay green, so it
reproduces the bug without redefining existing behaviour.

* fix(popover): split the wheel-shim opt-in from the scroll-container styling

Two fixes on top of the reviewer's round.

**The reviewer's change, kept.** `resolvePopoverScroller` no longer falls back to
the content element unconditionally; it must match the overflow test like any
other candidate. The reviewer flagged that this could break the existing opted-in
popovers, so I checked: `.popover-scroll-content` sets `overflow-y: auto`
(main.css:601-607), so every one of them still resolves. The test needs an inline
style only because happy-dom does not apply the stylesheet -- noted in the test so
nobody reads it as a production concern.

**A bug of mine the review did not reach.** Opting the cleanup Filters panel in via
`popover-scroll-content` would also have applied that class's
`max-height: min(15rem, ...)`, crushing the panel's 471px flex column to 240px.
The class conflates 'style me as a scroll container' with 'run the wheel shim', and
a popover that manages its own layout needs only the second.

So the shim now accepts `popover-wheel-scroll` as a styling-free marker, and the
Filters panel uses that. `popover-scroll-content` keeps implying it, so no existing
caller changes.
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…4629)

* fix(workspace-cleanup): make the filter panel scrollable

The height cap sat on the ScrollArea Root, but the Radix viewport inside is
h-full — under an indefinite root height that collapses to auto, so the
viewport grew to full content height with nothing to scroll while the root
clipped at 420px. The last facet groups (Archived, and the tail of Workspace
status) were unreachable behind the footer.

Move the cap to the viewport, which is what the ScrollArea wrapper's
viewportClassName exists for. Adds a regression test that pins the cap to the
viewport; it fails against the previous markup.

* fix(workspace-cleanup): keep filter footer visible
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…every filter patch (stablyai#15298)

A profile carried `activity.idleMinDays = 20` that the user never set, hiding 253
of 799 workspaces on open. Chromium mutates a *focused* number input on every wheel
tick, and before stablyai#14629 the facet panel could not scroll, so the natural response --
cursor into the panel, spin the wheel -- walked the threshold up and persisted it.

Two fixes:

- `FacetNumberField` renders `type="text" inputMode="numeric"`. A wheel cannot
  mutate a text input, and the parser already takes strings. `preventDefault` on a
  focused number input would also work, but it blocks the wheel's default action --
  which includes scrolling the nearest scrollable ancestor -- and would re-break the
  panel scrolling stablyai#14629 just fixed, in exactly the reported gesture. All five
  numeric facets share this one field.
- `patchFilters` closed over the render's `browse` snapshot, so two patches in one
  tick dropped one. It now writes through a functional update against the latest
  store state. `toggleSortField` and `clearFilters` had the same defect.

Both tests were confirmed to fail against the unfixed source before being kept.
enrick-dev pushed a commit to enrick-dev/orca that referenced this pull request Oct 15, 2026
…e content (stablyai#16206)

* fix(popover): wheel-scroll a popover whose scroller is nested, not the content

The workspace-cleanup Filters panel cannot be scrolled with a wheel. Only the
scrollbar drag and focus-scroll work. Two independent Electron QA passes measured
it on main: wheel events over that popover arrive defaultPrevented, panel
scrollTop 0 -> 0, while the candidate list inside the dialog subtree scrolls
normally.

Cause: the popover portals outside the Radix dialog subtree, so
react-remove-scroll's scroll-lock cancels wheel there. stablyai#14629 added a shim for
exactly this, but it scrolls `event.currentTarget` -- the PopoverContent -- and
only when that element is itself overflowing. The Filters panel is a flex column
holding a ScrollArea above a pinned footer, so PopoverContent is overflow-hidden
and the real scroller is a descendant. The shim looked at the wrong element and
returned early.

The shim now resolves the nearest scrollable element between the wheel target and
the content, inclusive of both, so it handles the nested-viewport shape as well as
the flat one. Still opt-in via `popover-scroll-content`; popovers without the
class are untouched. The cleanup Filters panel opts in.

This is the unfixed half of the original report. stablyai#14629 fixed the panel being
clipped; the wheel -- what you actually reach for -- stayed dead.

The nested test fails against the shipped shim and the other two stay green, so it
reproduces the bug without redefining existing behaviour.

* fix(popover): split the wheel-shim opt-in from the scroll-container styling

Two fixes on top of the reviewer's round.

**The reviewer's change, kept.** `resolvePopoverScroller` no longer falls back to
the content element unconditionally; it must match the overflow test like any
other candidate. The reviewer flagged that this could break the existing opted-in
popovers, so I checked: `.popover-scroll-content` sets `overflow-y: auto`
(main.css:601-607), so every one of them still resolves. The test needs an inline
style only because happy-dom does not apply the stylesheet -- noted in the test so
nobody reads it as a production concern.

**A bug of mine the review did not reach.** Opting the cleanup Filters panel in via
`popover-scroll-content` would also have applied that class's
`max-height: min(15rem, ...)`, crushing the panel's 471px flex column to 240px.
The class conflates 'style me as a scroll container' with 'run the wheel shim', and
a popover that manages its own layout needs only the second.

So the shim now accepts `popover-wheel-scroll` as a styling-free marker, and the
Filters panel uses that. `popover-scroll-content` keeps implying it, so no existing
caller changes.
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.

Workspace cleanup: Filters panel is clipped and cannot be scrolled

1 participant