feat(linear): functional Filter button + fix PATCH /api/issues 404#10
Open
obvious-autobuild[bot] wants to merge 3 commits into
Open
feat(linear): functional Filter button + fix PATCH /api/issues 404#10obvious-autobuild[bot] wants to merge 3 commits into
obvious-autobuild[bot] wants to merge 3 commits into
Conversation
Netlify PR PreviewsBase:
Replay QA
|
Author
|
Both open bugs from this QA run are addressed in the latest push (e7b7019):
A fresh QA run should pick up these fixes. |
added 3 commits
June 16, 2026 17:05
The "Filter" button in the issue list header was purely decorative — a Button with no onClick and no filter state — so users could not narrow the visible issue list beyond the sidebar view. Add a filter popover anchored to the button that filters issues by status, priority, and assignee on top of the existing view filter: - issue-filters.ts: pure `IssueFilters` type plus `applyIssueFilters` (composes view filter then status/priority/assignee) and `countActiveFilters`. Empty dimension = no constraint; dimensions combine with AND. - ui-store.ts: `filters` state with `setFilters`/`clearFilters`, following the existing Zustand pattern. - issue-filter-popover.tsx: Radix Popover + Checkbox built from existing UI primitives, with a count badge on the trigger, a clear action, and a loading/empty state for assignees. - main-view.tsx: wire the popover in and show a filter-aware empty state with a clear-filters action when no issues match.
Replay QA flagged a redundant /api/users refetch on page load. The shared `useUsers` query (consumed by the issue list, issue detail, and the new filter popover's assignee section) had no staleTime, so React Query treated cached user data as immediately stale and refetched it. Users are reference data that rarely change within a session — add a 5-minute staleTime so the cached result is reused across consumers.
The backend stored issues in a module-level array. Netlify scales functions out to multiple isolated instances, so an issue created or deleted on one instance was invisible to a request routed to another: PATCH /api/issues/:id intermittently returned 404 and status changes never persisted. Reproduced on the preview deploy: a freshly created issue 404'd on ~70% of concurrent PATCHes while seeded issues (present in every instance's initial array) always succeeded. Back the issue collection with Netlify Blobs (getDeployStore, strong consistency) seeded from the static seed data, giving every instance one shared, durable view. A local in-memory fallback keeps `netlify dev` working when the Blobs backend is unavailable. Also tolerate an optional trailing slash on /issues/:id so PATCH/DELETE match consistently.
e7b7019 to
7a5df18
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Two issues in the
linearapp, both surfaced while making the Filter control work:main-view.tsxthe button rendered the Filter icon + label with noonClick, no state, and no UI — users could not narrow the issue list at all.PATCH /api/issues/:idintermittently 404'd, so status changes never stuck. The backend kept issues in a module-level array. Netlify scales functions out to multiple isolated instances, so an issue created (or deleted) on one instance was invisible to a request routed to another. Reproduced on the preview deploy: a freshly created issue 404'd on ~70% of concurrent PATCHes, while seeded issues (present in every instance's initial array) always succeeded.What
Filter feature — A Radix popover anchored to the Filter button lets users filter by status, priority, and assignee. Selections compose on top of the existing sidebar view filter (view filter first, then user filters); empty in a dimension means "no constraint". A count badge shows active filters, a clear action resets them, and a filter-aware empty state renders when nothing matches. New filtering logic lives in
lib/issue-filters.ts(applyIssueFilters,countActiveFilters); filter state follows the existing Zustandui-storepattern. The new assignee-row avatars use main'sgetContrastTextColorso initials stay AA-readable.PATCH 404 (root cause) — Backed the issue collection with Netlify Blobs (
getDeployStore, strong consistency), seeded from the static seed data, so every function instance shares one durable view. A local in-memory fallback keepsnetlify devworking when Blobs is unavailable. The route regex now tolerates an optional trailing slash. Create/list/search/delete all go through the shared store, so no route can desync.How to Review
components/issue-filter-popover.tsx,components/main-view.tsx,lib/issue-filters.ts,store/ui-store.ts.netlify/functions/lib/issue-store.ts(new durable store),netlify/functions/api.mts(routes now async + trailing-slash tolerant),netlify/functions/lib/data.ts(seed split intoSEED_ISSUES/SEED_COUNTERS,makeIssuenow pure).main; the avatar-contrast work is now main'sgetContrastTextColor, reused (not re-implemented) at the new filter-popover call site.Test Evidence
vite buildsucceeds (no runtime errors). Lint clean for all changed/new files (3 remaining errors are pre-existing in untouched files — confirmed on basemain).200/404(~70% 404); 30 concurrent PATCHes on a seeded issue all returned200. After the Blobs-backed store, creates persist across instances.npm ci --dry-runpasses with the updatedpackage-lock.json(adds@netlify/blobs).Acceptance Criteria