Task tray
ProWork running in the background, as one pill: how many are running and how many need you. Opens to the list, needs-you first. Progress is shown only when the service knows the total; otherwise the task just says it's running. A task with lastHeardAt that has been silent past staleAfter, or whose host is offline, isn't counted as running: it says "No update since 10:42" or that its host is offline, and the pill counts it as not heard from.
Preview
Install
First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/task-tray
Brings in: agent-avatar, locale, popover, relative-time, run-heartbeat, status, status-dot, step-list, work, utils · npm: lucide-react@^1.67.0
Usage
"use client"
import type { BackgroundTask } from "@/lib/work"
import { TaskTray } from "@/components/task-tray"
const ago = (m: number) => new Date(Date.now() - m * 60_000).toISOString()
const tasks: BackgroundTask[] = [
{ id: "t1", title: "Add region to customers", status: "running", agent: { id: "a-dev", name: "Dev agent", role: "dev" }, progress: { done: 4, total: 6 }, startedAt: ago(3) },
{ id: "t2", title: "Drop partner_tier_old", status: "waiting", agent: { id: "a-orch", name: "Keel", role: "orchestrator" }, startedAt: ago(60 * 20), needs: "Waiting for another approver" },
{ id: "t3", title: "Audit API rate limits", status: "running", agent: { id: "a-qa", name: "QA agent", role: "qa" }, startedAt: ago(12) },
// Silent for 9 minutes: not counted as running, it says when it was last heard from.
{ id: "t5", title: "Backfill order totals", status: "running", startedAt: ago(30), lastHeardAt: ago(9) },
{ id: "t4", title: "Explain the invoice retry job", status: "succeeded", startedAt: ago(40) },
]
export default function Example() {
return <TaskTray tasks={tasks} onOpenTask={() => {}} />
}<TaskTray>
| Prop | Type | Default | Description |
|---|---|---|---|
| tasksrequired | BackgroundTask[] | — | The background tasks; with none, the tray renders nothing. |
| onOpenTask | ((id: string) => void) | undefined | — | Called with a task's id when it's clicked in the list. |
| staleAfter | number | undefined | STALE_AFTER | How long a running task may be silent before it's no longer called running, in milliseconds. Defaults to two minutes. |
| className | string | undefined | — | Extra classes for the outer element. |
Strings
The fixed words, in English by default. Change any of them under taskTray in <LocaleProvider strings={{ … }}>; the table is exported as taskTrayStrings.
| Key | English |
|---|---|
| running | {count} running |
| notHeard | { one: "{count} not heard from", other: "{count} not heard from" } |
| startedCount | {count} started |
| needsYou | { one: "{count} needs you", other: "{count} need you" } |
| allDone | All done |
| backgroundWork | Background work |
| progress | Step {done} of {total} |
| statusRunning | Running |
| statusFinished | Finished |
| statusQueued | Queued |
| started | {status} · started |