From ea3de8ab10582af4f9442bf2ef10e89a1c8c6a9c Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 16 Jul 2026 10:38:22 +0100 Subject: [PATCH 1/8] feat(inbox): add "Any" option to Source and Priority filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../inbox/components/InboxSearchFilterBar.tsx | 35 +++++++++++++++++++ .../stores/inboxSignalsFilterStore.test.ts | 28 +++++++++++++++ .../inbox/stores/inboxSignalsFilterStore.ts | 6 ++++ 3 files changed, 69 insertions(+) diff --git a/packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx b/packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx index 5fff5f42c2..8b728cc06c 100644 --- a/packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx +++ b/packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx @@ -40,8 +40,14 @@ export function InboxSearchFilterBar({ const toggleSourceProduct = useInboxSignalsFilterStore( (s) => s.toggleSourceProduct, ); + const clearSourceProductFilter = useInboxSignalsFilterStore( + (s) => s.clearSourceProductFilter, + ); const priorityFilter = useInboxSignalsFilterStore((s) => s.priorityFilter); const togglePriority = useInboxSignalsFilterStore((s) => s.togglePriority); + const clearPriorityFilter = useInboxSignalsFilterStore( + (s) => s.clearPriorityFilter, + ); const activeSort = INBOX_SORT_OPTIONS.find( (option) => @@ -73,6 +79,11 @@ export function InboxSearchFilterBar({ active={sourceProductFilter.length > 0} > + {INBOX_SOURCE_OPTIONS.map((option) => { const isActive = sourceProductFilter.includes(option.value); return ( @@ -132,6 +143,11 @@ export function InboxSearchFilterBar({ active={priorityFilter.length > 0} > + {INBOX_PRIORITY_OPTIONS.map((option) => { const isActive = priorityFilter.includes(option.value); return ( @@ -160,6 +176,25 @@ export function InboxSearchFilterBar({ ); } +function InboxFilterAnyItem({ + label, + active, + onClick, +}: { + label: string; + active: boolean; + onClick: () => void; +}) { + return ( + + ); +} + function InboxFilterPopover({ label, value, diff --git a/packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.test.ts b/packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.test.ts index 64d14bd553..044f913674 100644 --- a/packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.test.ts +++ b/packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.test.ts @@ -71,6 +71,34 @@ describe("inboxSignalsFilterStore", () => { ]); }); + it("clearPriorityFilter resets priorities back to Any (empty)", () => { + useInboxSignalsFilterStore.getState().setPriorityFilter(["P0", "P1"]); + + useInboxSignalsFilterStore.getState().clearPriorityFilter(); + + expect(useInboxSignalsFilterStore.getState().priorityFilter).toEqual([]); + }); + + it("clearSourceProductFilter resets sources back to Any (empty)", () => { + useInboxSignalsFilterStore.getState().toggleSourceProduct("github"); + useInboxSignalsFilterStore.getState().toggleSourceProduct("linear"); + + useInboxSignalsFilterStore.getState().clearSourceProductFilter(); + + expect(useInboxSignalsFilterStore.getState().sourceProductFilter).toEqual( + [], + ); + }); + + it("toggling off the last source is equivalent to Any (empty)", () => { + useInboxSignalsFilterStore.getState().toggleSourceProduct("github"); + useInboxSignalsFilterStore.getState().toggleSourceProduct("github"); + + expect(useInboxSignalsFilterStore.getState().sourceProductFilter).toEqual( + [], + ); + }); + it("setPriorityFilter de-duplicates priorities", () => { useInboxSignalsFilterStore.getState().setPriorityFilter(["P0", "P1", "P0"]); diff --git a/packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.ts b/packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.ts index 33f25ef3bb..feb3348114 100644 --- a/packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.ts +++ b/packages/ui/src/features/inbox/stores/inboxSignalsFilterStore.ts @@ -31,6 +31,10 @@ interface InboxSignalsFilterActions { toggleSourceProduct: (source: SourceProduct) => void; togglePriority: (priority: SignalReportPriority) => void; setPriorityFilter: (priorities: SignalReportPriority[]) => void; + /** Clear the source filter back to "Any" (empty = all sources). */ + clearSourceProductFilter: () => void; + /** Clear the priority filter back to "Any" (empty = all priorities). */ + clearPriorityFilter: () => void; /** Reset all filters when a deep link arrives so the linked report isn't hidden. */ resetFilters: () => void; } @@ -74,6 +78,8 @@ export const useInboxSignalsFilterStore = create()( set({ priorityFilter: Array.from(new Set(priorities)), }), + clearSourceProductFilter: () => set({ sourceProductFilter: [] }), + clearPriorityFilter: () => set({ priorityFilter: [] }), resetFilters: () => set({ searchQuery: "", From 50dabb5b8659563d56477b8189c8ad50a1df5312 Mon Sep 17 00:00:00 2001 From: Paul D'Ambra Date: Thu, 16 Jul 2026 10:50:46 +0100 Subject: [PATCH 2/8] fix(inbox): drop speculative label prop on InboxFilterAnyItem Generated-By: PostHog Code Task-Id: 97aa95fe-d9a3-4651-aa9b-9f636fc84832 --- .../src/features/inbox/components/InboxSearchFilterBar.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx b/packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx index 8b728cc06c..846a629c53 100644 --- a/packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx +++ b/packages/ui/src/features/inbox/components/InboxSearchFilterBar.tsx @@ -80,7 +80,6 @@ export function InboxSearchFilterBar({ > @@ -144,7 +143,6 @@ export function InboxSearchFilterBar({ > @@ -177,17 +175,15 @@ export function InboxSearchFilterBar({ } function InboxFilterAnyItem({ - label, active, onClick, }: { - label: string; active: boolean; onClick: () => void; }) { return (