fix(tasks): don't flash the Slack icon on newly created tasks#2672
Conversation
useCreateTask optimistically inserted the new task into every task-list cache via setQueriesData on the taskKeys.lists() prefix, which also matches the slack-origin list read by useSlackTasks. The sidebar derives a task's origin (and Slack icon) by id membership in that list because the summaries endpoint omits origin_product, so a freshly created, non-slack task briefly rendered as a Slack task until the list refetched. Scope the optimistic insert to lists that aren't filtered by origin_product so the slack-origin cache stays clean. Generated-By: PostHog Code Task-Id: d2ed2d1b-2570-49a9-aa60-87e235a904f1
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
Prompt To Fix All With AIFix the following 1 code review issue. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 1
packages/ui/src/features/tasks/useTaskCrudMutations.test.tsx:96-117
**Prefer parameterised tests**
The single `it` block verifies the slack case, but the predicate `!filters?.originProduct` is meant to exclude *any* origin-product-filtered cache, not just slack. A parameterised test would prove the fix holds for other origin products (e.g. `"linear"`, `"github"`) and that caches filtered only by non-`originProduct` fields (e.g. `{ repository: "my-repo" }`) are still optimistically seeded as intended. Testing only the slack example leaves the more general contract implicit.
Reviews (1): Last reviewed commit: "fix(tasks): don't seed the slack-origin ..." | Re-trigger Greptile |
| it("seeds plain list caches but not the slack-origin list", () => { | ||
| const queryClient = new QueryClient(); | ||
| const plainKey = taskKeys.list(); | ||
| const slackKey = taskKeys.list({ originProduct: "slack" }); | ||
| queryClient.setQueryData<Task[]>(plainKey, []); | ||
| queryClient.setQueryData<Task[]>(slackKey, []); | ||
|
|
||
| const localWrapper = ({ children }: { children: ReactNode }) => ( | ||
| <QueryClientProvider client={queryClient}>{children}</QueryClientProvider> | ||
| ); | ||
| const { result } = renderHook(() => useCreateTask(), { | ||
| wrapper: localWrapper, | ||
| }); | ||
|
|
||
| result.current.invalidateTasks(createTask()); | ||
|
|
||
| // The new, non-slack task lands in the plain list... | ||
| expect(queryClient.getQueryData<Task[]>(plainKey)).toHaveLength(1); | ||
| // ...but never pollutes the slack-origin list, which the sidebar reads to | ||
| // brand task icons by id membership. | ||
| expect(queryClient.getQueryData<Task[]>(slackKey)).toHaveLength(0); | ||
| }); |
There was a problem hiding this comment.
The single it block verifies the slack case, but the predicate !filters?.originProduct is meant to exclude any origin-product-filtered cache, not just slack. A parameterised test would prove the fix holds for other origin products (e.g. "linear", "github") and that caches filtered only by non-originProduct fields (e.g. { repository: "my-repo" }) are still optimistically seeded as intended. Testing only the slack example leaves the more general contract implicit.
Context Used: Do not attempt to comment on incorrect alphabetica... (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/ui/src/features/tasks/useTaskCrudMutations.test.tsx
Line: 96-117
Comment:
**Prefer parameterised tests**
The single `it` block verifies the slack case, but the predicate `!filters?.originProduct` is meant to exclude *any* origin-product-filtered cache, not just slack. A parameterised test would prove the fix holds for other origin products (e.g. `"linear"`, `"github"`) and that caches filtered only by non-`originProduct` fields (e.g. `{ repository: "my-repo" }`) are still optimistically seeded as intended. Testing only the slack example leaves the more general contract implicit.
**Context Used:** Do not attempt to comment on incorrect alphabetica... ([source](https://app.greptile.com/review/custom-context?memory=instruction-0))
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
|
Note 🤖 Automated comment by QA Swarm — not written by a human Multi-perspective review: paul-reviewer, xp-reviewer, security-audit (qa-team skipped — not present in this repo) Verdict: 💬 APPROVE WITH NITSCorrect, well-targeted fix for a real, subtle bug. No correctness or security issues. One convergent design nit worth a look; the rest are optional. Convergence (highest confidence — flagged independently by paul + xp)
Nits (optional)
Reviewer summaries
Automated by QA Swarm — not a human review |
Address qa-swarm review (paul + xp convergent): the create-task seed predicate reached into the query key by positional index (queryKey[2]) and re-declared a partial filters type, duplicating key-shape knowledge that belongs with taskKeys. A future key-shape change would silently reintroduce the Slack-icon bug with no test failure. - Add `TaskListFilters` type and a `taskKeys.filtersOf(queryKey)` accessor so the shape lives OnceAndOnlyOnce beside `list()`. - Name the predicate's intent (`isOriginScopedList`) and finish the comment so code and intent agree (any origin-scoped list, not just slack). - Parameterise the seed test across plain/repository/slack lists and add a test asserting all lists are still invalidated (refetched). Generated-By: PostHog Code Task-Id: d2ed2d1b-2570-49a9-aa60-87e235a904f1
|
Note 🤖 Automated comment by PR Shepherd — not written by a human Actioned the qa-swarm review in 6185233:
security-audit: no findings. All 6 tests pass, typecheck + biome clean. |
Problem
A newly created task in posthog/code would sometimes flash the Slack icon while it was still loading, even though it wasn't a Slack-triggered task. It self-corrected a moment later.
Root cause:
useCreateTask.invalidateTasksoptimistically inserts the new task into every task-list cache viasetQueriesData({ queryKey: taskKeys.lists() }, ...), andtaskKeys.lists()prefix-matches the slack-origin list too (useSlackTasks). Because/tasks/summaries/omitsorigin_product, the sidebar infers a task's Slack origin purely by id membership in that slack list (buildSidebarData.ts). So the freshly created, non-slack task landed inslackTaskIdsand rendered the Slack icon untiluseSlackTasksrefetched from the server and dropped it.Changes
Scope the optimistic insert to list caches that aren't filtered by
origin_product, using apredicatethat skips any list query whose filter hasoriginProductset. The slack-origin cache stays clean, so the new task never transiently shows the Slack icon.How did you test this?
useTaskCrudMutations.test.tsxassertinginvalidateTasksseeds the plain list but not the slack-origin list.pnpm exec vitest run useTaskCrudMutations.test.tsx→ 3 passed.biome lintclean on both changed files.pnpm --filter @posthog/ui typecheckpasses.Automatic notifications
Created with PostHog Code from a Slack thread