Adds the visible front-end and the worker back-end for the agent
task system. The PocketBase schema, API routes, and ToastProvider
were already in the previous commit; this commit completes the
picture.
UI
- app/tasks/{page,KanbanBoard,TaskCard,CardModal,TaskDetail,api,columns}
Full Kanban with six columns (Backlog, Ready, In Progress,
Blocked, Done, Failed), drag-and-drop between columns, quick-add
chips, type/priority filters, task detail panel with retry/cancel/
delete, 5s polling, transition toasts.
- components/NavBar.tsx: 'Tasks' link in primary nav.
- app/bizportal-2/BizPortal2Explorer.tsx: 'Send to Kanban' button
on the result view — dispatches the current search to the agent
queue as a 'ready' task.
Back-end
- scripts/task_worker.py: PocketBase polling worker with two
lanes. Deterministic handles bizportal_search/reserve, pdf_generate,
email_send. Custom lane writes to /tmp/agent_inbox/ for the
LLM agent to pick up. Atomic claim via PB filter, auto-retry up
to 3x, structured log on each task.
- scripts/bizportal_service.py: bugfix — _is_logged_in was using
a non-CSS selector so session-recovery was a no-op. Also made
the login flow re-runnable mid-session (handles BizPortal's
~20-minute session timeout transparently).
- scripts/init_pb_schema.py: duration_ms no longer capped at 0.
Verified end-to-end:
- CK search via worker: 1 company, 3 directors, ~10s
- ID search via worker: 4 companies, 7 total directors, ~34s
- Auto-retry + status transitions + toast fires
57 lines
2.5 KiB
TypeScript
57 lines
2.5 KiB
TypeScript
// app/tasks/columns.ts
|
|
// Column definitions for the Kanban. Status → display config.
|
|
|
|
export type TaskStatus = "backlog" | "ready" | "in_progress" | "blocked" | "done" | "failed";
|
|
export type TaskPriority = "low" | "normal" | "high" | "urgent";
|
|
export type TaskType = "bizportal_search" | "bizportal_reserve" | "pdf_generate" | "email_send" | "custom";
|
|
|
|
export const COLUMNS: { id: TaskStatus; title: string; hint: string; accent: string }[] = [
|
|
{ id: "backlog", title: "Backlog", hint: "Not yet ready", accent: "border-border" },
|
|
{ id: "ready", title: "Ready", hint: "Agent can pick up", accent: "border-blue-300" },
|
|
{ id: "in_progress", title: "In Progress", hint: "Agent is working", accent: "border-amber-300" },
|
|
{ id: "blocked", title: "Blocked", hint: "Needs human input", accent: "border-red-300" },
|
|
{ id: "done", title: "Done", hint: "Completed", accent: "border-green-300" },
|
|
{ id: "failed", title: "Failed", hint: "Error — retry or discard", accent: "border-red-400" },
|
|
];
|
|
|
|
export const PRIORITY_COLORS: Record<TaskPriority, string> = {
|
|
low: "bg-gray-100 text-gray-700 border-gray-200",
|
|
normal: "bg-blue-50 text-blue-700 border-blue-200",
|
|
high: "bg-amber-100 text-amber-800 border-amber-300",
|
|
urgent: "bg-red-100 text-red-800 border-red-300",
|
|
};
|
|
|
|
export const TASK_TYPE_META: Record<TaskType, { label: string; icon: string; tone: string }> = {
|
|
bizportal_search: { label: "BizPortal · search", icon: "🔍", tone: "bg-emerald-50 text-emerald-800 border-emerald-200" },
|
|
bizportal_reserve: { label: "BizPortal · reserve", icon: "📝", tone: "bg-emerald-50 text-emerald-800 border-emerald-200" },
|
|
pdf_generate: { label: "PDF · generate", icon: "📄", tone: "bg-violet-50 text-violet-800 border-violet-200" },
|
|
email_send: { label: "Email · send", icon: "✉️", tone: "bg-sky-50 text-sky-800 border-sky-200" },
|
|
custom: { label: "Custom", icon: "🧩", tone: "bg-slate-50 text-slate-800 border-slate-200" },
|
|
};
|
|
|
|
export const TASK_TYPE_LABEL: Record<TaskType, string> = {
|
|
bizportal_search: "BizPortal search",
|
|
bizportal_reserve: "BizPortal name reservation",
|
|
pdf_generate: "PDF generation",
|
|
email_send: "Email send",
|
|
custom: "Custom task",
|
|
};
|
|
|
|
export const PRIORITY_LABEL: Record<TaskPriority, string> = {
|
|
low: "Low",
|
|
normal: "Normal",
|
|
high: "High",
|
|
urgent: "Urgent",
|
|
};
|
|
|
|
export const STATUS_LABEL: Record<TaskStatus, string> = {
|
|
backlog: "Backlog",
|
|
ready: "Ready",
|
|
in_progress: "In Progress",
|
|
blocked: "Blocked",
|
|
done: "Done",
|
|
failed: "Failed",
|
|
};
|
|
|
|
// 7 days in done auto-collapse
|
|
export const DONE_COLLAPSE_DAYS = 7;
|