feat(hybridFilter): add shift-click range selection#108294
feat(hybridFilter): add shift-click range selection#108294
Conversation
Moves checkbox position to the beginning of the row and unwinds the mess of checkwraps. <img width="666" height="624" alt="CleanShot 2026-02-11 at 16 28 05@2x" src="https://github.com/user-attachments/assets/4fe46a08-9619-49b7-9377-fb58088495cb" /> Fix DE-752
…dFilter - Created useStagedCompactSelect hook that encapsulates all state management and business logic for staged selection (commit/cancel/toggle) - Manages modifier key detection for hybrid single/multiple selection mode - Hook returns all handlers and state as a single object (stagedSelect) - Component now focuses on UI rendering while hook handles state logic - All existing tests pass, no behavior changes
…electProps
- Hook now returns a typed `props` object that matches CompactSelectProps
- Props can be spread directly into CompactSelect: {...stagedSelect.props}
- Separates CompactSelect props from utility functions (commit, toggleOption, etc)
- Improves type safety and makes hook more reusable
- All tests pass, no behavior changes
The Reset button in the refactored HybridFilter components doesn't have an aria-label attribute, so the test needs to find it by its text content instead. This fixes the failing acceptance test for test_global_selection_header_updates_environment_with_browser_navigation_buttons.
Co-authored-by: Jonas <[email protected]>
…lButton Co-authored-by: Jonas <[email protected]>
Implements shift-click multi-selection for hybrid filter components, allowing users to select a range of items by holding shift and clicking. This works alongside existing Cmd/Ctrl modifier for individual toggles. - Separate shift key detection from Cmd/Ctrl modifiers - Add range selection logic that selects all items between anchor and clicked item - Extract performSingleToggle helper to reduce code duplication - Track last selected item as anchor point for range selection - Clear text selection on shift-click to prevent UI glitches - Keep menu open during shift operations - Add comprehensive unit tests for shift-click functionality - Update all consumers to pass options array to hook
- Use Ctrl+row clicks to set anchor instead of checkbox clicks - This ensures keyboard events are properly captured by CompactSelect - Fix array ordering in shiftToggleRange to preserve option order - All 13 tests now passing
The text selection clearing isn't needed for the shift-click functionality.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| if (!lastSelectedRef.current) { | ||
| performSingleToggle(clickedValue); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Falsy check fails for valid zero-value anchors
Medium Severity
The !lastSelectedRef.current check uses a falsy test to detect whether an anchor has been set. Since lastSelectedRef is typed as Value | null where Value extends SelectKey (string | number), a valid anchor value of 0 (or "") would be treated as "no anchor," causing shiftToggleRange to fall back to performSingleToggle instead of performing range selection. The project page filter uses number values for project IDs, making this reachable. The check needs to be a strict === null comparison.
| useState, | ||
| } from 'react'; | ||
| import styled from '@emotion/styled'; | ||
| import {isAppleDevice, isMac} from '@react-aria/utils'; |
There was a problem hiding this comment.
Orphaned utility after removing its only import
Low Severity
The isModifierKeyPressed utility in static/app/utils/isModifierKeyPressed.tsx is now dead code — this PR removed its only import (from hybridFilter.tsx) and inlined the modifier detection logic directly using isAppleDevice and isMac from @react-aria/utils. No other file in the codebase imports isModifierKeyPressed.
| const getFlatOptions = useCallback( | ||
| (opts: Array<SelectOptionOrSection<Value>>): Array<SelectOption<Value>> => { | ||
| return opts.flatMap(item => ('options' in item ? item.options : [item])); | ||
| }, | ||
| [] | ||
| ); |
There was a problem hiding this comment.
we must have this code a bazillion times 😂
Split away from #108294 as we de didn't merge the upstream change
Split away from #108294 as we de didn't merge the upstream change


Implements range selection via shift click making it less tedious to select multiple projects at once (currently requires clicking each checkbox)