feat(web): add redispatch action to board card for failed/cancelled tasks #1190

Closed
dev wants to merge 1 commit from dev/1169-board-redispatch into dev/0
Collaborator

Closes #1169

Summary

  • Extracts canRedispatch(status) into apps/web/src/lib/task-utils.ts so the board card and the task-list sidebar share one implementation
  • Updates task-list.tsx to import canRedispatch from task-utils (removes the inline status === "failure" || status === "cancelled" check)
  • Updates board-card.tsx to use canRedispatch(card.last_task_status) instead of a bare truthy check

The RedispatchButton component, onRedispatch prop wiring through BoardBoardCardView, the route-level redispatchMutation, and the SSE-driven board invalidation were already in place from prior work; this PR completes the feature by adding the shared utility and connecting it.

Test plan

  • just qa passes (typecheck + lint + format + tests)
  • Board card shows RotateCcw icon button on cards whose last_task_status is failure, cancelled, or interrupted
  • Button is absent on running/queued/idle cards
  • Click triggers POST /task/:id/redispatch; on success a toast shows and the card disappears from the Error/Abandoned column via SSE invalidation
  • On network error, a toast shows the error message
  • Task-list sidebar redispatch button still works (no regression)
Closes #1169 ## Summary - Extracts `canRedispatch(status)` into `apps/web/src/lib/task-utils.ts` so the board card and the task-list sidebar share one implementation - Updates `task-list.tsx` to import `canRedispatch` from `task-utils` (removes the inline `status === "failure" || status === "cancelled"` check) - Updates `board-card.tsx` to use `canRedispatch(card.last_task_status)` instead of a bare truthy check The `RedispatchButton` component, `onRedispatch` prop wiring through `Board` → `BoardCardView`, the route-level `redispatchMutation`, and the SSE-driven board invalidation were already in place from prior work; this PR completes the feature by adding the shared utility and connecting it. ## Test plan - [ ] `just qa` passes (typecheck + lint + format + tests) - [ ] Board card shows RotateCcw icon button on cards whose `last_task_status` is `failure`, `cancelled`, or `interrupted` - [ ] Button is absent on running/queued/idle cards - [ ] Click triggers `POST /task/:id/redispatch`; on success a toast shows and the card disappears from the Error/Abandoned column via SSE invalidation - [ ] On network error, a toast shows the error message - [ ] Task-list sidebar redispatch button still works (no regression)
Closes #1169

- Extract `canRedispatch(status)` into `lib/task-utils.ts` so board card
  and task-list sidebar share one implementation
- Use `canRedispatch` in `task-list.tsx` (replaces inline check)
- Use `canRedispatch` in `board-card.tsx` (replaces bare truthy check on
  `last_task_status`); the `RedispatchButton` + `onRedispatch` prop wire
  was already in place from prior work

Co-authored-by: Cursor <cursoragent@cursor.com>
dev requested review from reviewer 2026-05-15 00:28:18 +00:00
reviewer approved these changes 2026-05-15 00:30:16 +00:00
reviewer left a comment

Review: PR #1190 — add redispatch action to board card

Reviewed against issue #1169 AC and the base PR (#1188) that introduced RedispatchButton, the mutation wiring, and the server-side last_task_id/last_task_status fields.

AC verification

Criterion Status
canRedispatch() extracted into lib/task-utils.ts
Board card shows button when canRedispatch is true (failure | cancelled | interrupted)
Button absent on running/queued/idle cards — enforced server-side in board-projection.ts
Click triggers POST /task/:id/redispatch via existing onRedispatch prop chain
On success: toast + invalidateQueries → SSE-driven card update (in #1188, unchanged here)
On error: toast with message (in #1188, unchanged here)
just qa passes ⚠️ CI state is null — no runs recorded yet

Code quality

task-utils.ts is clean:

  • ReadonlySet<TaskStatus> avoids repeated string comparisons and is immutable by contract.
  • status: TaskStatus | null | undefined signature matches all call-sites (card.last_task_status is optional on the wire type; task.status from task-list is always present but typed broadly).
  • The !!status && guard before the Set lookup is correct.

board-card.tsx fix is correct. In practice the old truthy check (card.last_task_status &&) was also safe because the server projection only populates the field for failure | cancelled | interrupted — but the explicit predicate is much clearer.

task-list.tsx rename (canRedispatch local → showRedispatch) avoids the variable-shadows-import ambiguity neatly.

Observations (non-blocking)

  1. interrupted added beyond issue AC. The issue lists {failure, cancelled} only, but this PR adds interrupted to canRedispatch (as the base PR's server code and shared type already do). This is the right call — an interrupted run is just as retryable — but worth a quick nod back to the issue author to close the loop.

  2. Icon: RotateCcw vs RotateCw. The issue spec says RotateCw; the base PR (#1188) implemented RotateCcw. This PR doesn't change it. Cosmetically both are reasonable; flag if the designer has a preference.

  3. CI not yet run. Please confirm just qa passes locally before merging (or wait for a CI green). The diff is low-risk but the check should be verified.

Summary

The extraction is clean and the gate condition fix is correct. LGTM pending a CI green.

## Review: PR #1190 — add redispatch action to board card Reviewed against issue #1169 AC and the base PR (#1188) that introduced `RedispatchButton`, the mutation wiring, and the server-side `last_task_id`/`last_task_status` fields. ### AC verification | Criterion | Status | |---|---| | `canRedispatch()` extracted into `lib/task-utils.ts` | ✅ | | Board card shows button when `canRedispatch` is true (`failure \| cancelled \| interrupted`) | ✅ | | Button absent on running/queued/idle cards — enforced server-side in `board-projection.ts` | ✅ | | Click triggers `POST /task/:id/redispatch` via existing `onRedispatch` prop chain | ✅ | | On success: toast + `invalidateQueries` → SSE-driven card update | ✅ (in #1188, unchanged here) | | On error: toast with message | ✅ (in #1188, unchanged here) | | `just qa` passes | ⚠️ CI state is `null` — no runs recorded yet | ### Code quality `task-utils.ts` is clean: - `ReadonlySet<TaskStatus>` avoids repeated string comparisons and is immutable by contract. - `status: TaskStatus | null | undefined` signature matches all call-sites (`card.last_task_status` is optional on the wire type; `task.status` from task-list is always present but typed broadly). - The `!!status &&` guard before the Set lookup is correct. `board-card.tsx` fix is correct. In practice the old truthy check (`card.last_task_status &&`) was also safe because the server projection only populates the field for `failure | cancelled | interrupted` — but the explicit predicate is much clearer. `task-list.tsx` rename (`canRedispatch` local → `showRedispatch`) avoids the variable-shadows-import ambiguity neatly. ### Observations (non-blocking) 1. **`interrupted` added beyond issue AC.** The issue lists `{failure, cancelled}` only, but this PR adds `interrupted` to `canRedispatch` (as the base PR's server code and shared type already do). This is the right call — an interrupted run is just as retryable — but worth a quick nod back to the issue author to close the loop. 2. **Icon: `RotateCcw` vs `RotateCw`.** The issue spec says `RotateCw`; the base PR (#1188) implemented `RotateCcw`. This PR doesn't change it. Cosmetically both are reasonable; flag if the designer has a preference. 3. **CI not yet run.** Please confirm `just qa` passes locally before merging (or wait for a CI green). The diff is low-risk but the check should be verified. ### Summary The extraction is clean and the gate condition fix is correct. LGTM pending a CI green.
claude-desktop closed this pull request 2026-05-15 08:58:29 +00:00

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/agent-hooks!1190
No description provided.