Skip to content

Commit ea3de8a

Browse files
authored
feat(inbox): add "Any" option to Source and Priority filters
The inbox Source and Priority filter popovers had no explicit way to go back to "no filter" — you had to manually unselect each choice. Add an "Any" row at the top of each popover that is checked when nothing else is selected and clears that filter when clicked. Unselecting the last option already collapses to the same empty ("Any") state. Generated-By: PostHog Code Task-Id: 97aa95fe-d9a3-4651-aa9b-9f636fc84832
1 parent 4f27d54 commit ea3de8a

3 files changed

Lines changed: 69 additions & 0 deletions

File tree

packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,14 @@ export function InboxSearchFilterBar({
4040
const toggleSourceProduct = useInboxSignalsFilterStore(
4141
(s) => s.toggleSourceProduct,
4242
);
43+
const clearSourceProductFilter = useInboxSignalsFilterStore(
44+
(s) => s.clearSourceProductFilter,
45+
);
4346
const priorityFilter = useInboxSignalsFilterStore((s) => s.priorityFilter);
4447
const togglePriority = useInboxSignalsFilterStore((s) => s.togglePriority);
48+
const clearPriorityFilter = useInboxSignalsFilterStore(
49+
(s) => s.clearPriorityFilter,
50+
);
4551

4652
const activeSort = INBOX_SORT_OPTIONS.find(
4753
(option) =>
@@ -73,6 +79,11 @@ export function InboxSearchFilterBar({
7379
active={sourceProductFilter.length > 0}
7480
>
7581
<Flex direction="column" gap="0">
82+
<InboxFilterAnyItem
83+
label="Any"
84+
active={sourceProductFilter.length === 0}
85+
onClick={clearSourceProductFilter}
86+
/>
7687
{INBOX_SOURCE_OPTIONS.map((option) => {
7788
const isActive = sourceProductFilter.includes(option.value);
7889
return (
@@ -132,6 +143,11 @@ export function InboxSearchFilterBar({
132143
active={priorityFilter.length > 0}
133144
>
134145
<Flex direction="column" gap="0">
146+
<InboxFilterAnyItem
147+
label="Any"
148+
active={priorityFilter.length === 0}
149+
onClick={clearPriorityFilter}
150+
/>
135151
{INBOX_PRIORITY_OPTIONS.map((option) => {
136152
const isActive = priorityFilter.includes(option.value);
137153
return (
@@ -160,6 +176,25 @@ export function InboxSearchFilterBar({
160176
);
161177
}
162178

179+
function InboxFilterAnyItem({
180+
label,
181+
active,
182+
onClick,
183+
}: {
184+
label: string;
185+
active: boolean;
186+
onClick: () => void;
187+
}) {
188+
return (
189+
<button type="button" className={FILTER_ITEM_CLASS} onClick={onClick}>
190+
<span className="truncate">{label}</span>
191+
{active ? (
192+
<CheckIcon size={12} className="shrink-0 text-gray-12" />
193+
) : null}
194+
</button>
195+
);
196+
}
197+
163198
function InboxFilterPopover({
164199
label,
165200
value,

packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,34 @@ describe("inboxSignalsFilterStore", () => {
7171
]);
7272
});
7373

74+
it("clearPriorityFilter resets priorities back to Any (empty)", () => {
75+
useInboxSignalsFilterStore.getState().setPriorityFilter(["P0", "P1"]);
76+
77+
useInboxSignalsFilterStore.getState().clearPriorityFilter();
78+
79+
expect(useInboxSignalsFilterStore.getState().priorityFilter).toEqual([]);
80+
});
81+
82+
it("clearSourceProductFilter resets sources back to Any (empty)", () => {
83+
useInboxSignalsFilterStore.getState().toggleSourceProduct("github");
84+
useInboxSignalsFilterStore.getState().toggleSourceProduct("linear");
85+
86+
useInboxSignalsFilterStore.getState().clearSourceProductFilter();
87+
88+
expect(useInboxSignalsFilterStore.getState().sourceProductFilter).toEqual(
89+
[],
90+
);
91+
});
92+
93+
it("toggling off the last source is equivalent to Any (empty)", () => {
94+
useInboxSignalsFilterStore.getState().toggleSourceProduct("github");
95+
useInboxSignalsFilterStore.getState().toggleSourceProduct("github");
96+
97+
expect(useInboxSignalsFilterStore.getState().sourceProductFilter).toEqual(
98+
[],
99+
);
100+
});
101+
74102
it("setPriorityFilter de-duplicates priorities", () => {
75103
useInboxSignalsFilterStore.getState().setPriorityFilter(["P0", "P1", "P0"]);
76104

packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ interface InboxSignalsFilterActions {
3131
toggleSourceProduct: (source: SourceProduct) => void;
3232
togglePriority: (priority: SignalReportPriority) => void;
3333
setPriorityFilter: (priorities: SignalReportPriority[]) => void;
34+
/** Clear the source filter back to "Any" (empty = all sources). */
35+
clearSourceProductFilter: () => void;
36+
/** Clear the priority filter back to "Any" (empty = all priorities). */
37+
clearPriorityFilter: () => void;
3438
/** Reset all filters when a deep link arrives so the linked report isn't hidden. */
3539
resetFilters: () => void;
3640
}
@@ -74,6 +78,8 @@ export const useInboxSignalsFilterStore = create<InboxSignalsFilterStore>()(
7478
set({
7579
priorityFilter: Array.from(new Set(priorities)),
7680
}),
81+
clearSourceProductFilter: () => set({ sourceProductFilter: [] }),
82+
clearPriorityFilter: () => set({ priorityFilter: [] }),
7783
resetFilters: () =>
7884
set({
7985
searchQuery: "",

0 commit comments

Comments
 (0)