8df1bda87b
* fix(web): show tasks from all workflows in the mobile task-switcher sheet The mobile sheet read tasks via useTasks(workflowId), which gated on kanban.workflowId === workflowId and returned [] otherwise. On a fresh /t/[id] load the gate often failed (or the snapshot fetch was still in flight / silently failing) and the sheet rendered "No tasks yet." Align mobile with desktop: read from kanbanMulti.snapshots via a new shared useWorkspaceSidebarTasks hook that does the per-workspace aggregation (incl. the active-kanban fallback), and pass workflows + stepsByWorkflowId through so the existing TaskSwitcher grouping kicks in. The desktop sidebar now delegates to the same hook. * refactor(web): address review comments on PR #1025 - Extract findTaskInSnapshots to task-select-helpers.ts (shared between desktop sidebar and mobile sheet). Mobile passes kanban.tasks as the optional fallback so it still locates tasks that arrived via WS before the snapshot fetch landed. - Build workflowNameById from the already-scoped `workflows` array instead of the raw, unscoped kanbanMulti.snapshots. Stops the memo from re-running on snapshot updates from other workspaces and removes the risk of a stale workflow name leaking across a workspace switch. Same fix in both the desktop sidebar and the mobile sheet. - Collapse the duplicated workflow filter in useWorkspaceSidebarTasks into a single `filteredWorkflows` memo. * fix(web): empty scope when workspaceId is unresolved in mobile/desktop sidebar hook When `useWorkspaceSidebarTasks` was called with a null workspaceId (the initial SSR / pre-hydration state on /t/[id]) it would widen to every workflow in the store, briefly leaking snapshots from previously-active workspaces into the sidebar. Return an empty scope until the workspace resolves instead, matching the "no cross-workspace bleed" intent of the original useScopedAggregation comment. Adds a regression test, plus splits the test file's describe block so the linter's 100-lines-per-function cap doesn't trip. * refactor(web): consolidate findTaskInSnapshots and drop unused useSheetData.steps - Reuse the canonical helper in `lib/kanban/find-task.ts` instead of duplicating it in `task-select-helpers.ts`. Extend the canonical one with an optional `fallbackTasks` parameter so the mobile sheet can still locate tasks via `state.kanban.tasks` when the snapshot fetch hasn't landed yet — desktop call sites continue to omit the fallback. - `useSheetData` was returning the raw active-kanban `steps` slice next to the already-mapped `dialogSteps`. The sheet component only consumes `dialogSteps`; drop the unused field. * test(web): add unit tests for findTaskInSnapshots fallback path * fix(web): pass active-kanban fallback into desktop sidebar task lookups useWorkspaceSidebarTasks can render tasks from the active kanban slice before kanbanMulti.snapshots catches up, but the desktop sidebar's archive/delete/select handlers were searching snapshots only — leaving fallback-only tasks unresolved during the snapshot race window. Pass state.kanban.tasks into findTaskInSnapshots in all three handlers so the dialogs find the right title and selectTaskWithLayout sees the task. Also trims the multi-line comment in lib/kanban/find-task.ts to a single line per CLAUDE.md style guidance. --------- Co-authored-by: Kandev Agent <agent@kandev.dev>
17 lines
596 B
TypeScript
17 lines
596 B
TypeScript
import type { KanbanState } from "@/lib/state/slices";
|
|
|
|
type Task = KanbanState["tasks"][number];
|
|
|
|
// `fallbackTasks` is consulted when no snapshot matches (e.g. WS-arrived tasks before their snapshot lands).
|
|
export function findTaskInSnapshots(
|
|
taskId: string,
|
|
snapshots: Record<string, { tasks: KanbanState["tasks"] }>,
|
|
fallbackTasks?: KanbanState["tasks"],
|
|
): Task | null {
|
|
for (const snapshot of Object.values(snapshots)) {
|
|
const found = snapshot.tasks.find((t) => t.id === taskId);
|
|
if (found) return found;
|
|
}
|
|
return fallbackTasks?.find((t) => t.id === taskId) ?? null;
|
|
}
|