feat(HAI-055): add failed task status handling with retry support

- Set task status to 'failed' on execution failure in engine executor
- Add failed indicator styling on TaskCard component
- Add POST /tasks/:id/retry API endpoint and client function
- Add retry button in TaskDetailModal for failed tasks
- Add tests for failed indicator, retry endpoint, and modal behavior
This commit is contained in:
Dustin Byrne
2026-03-25 23:50:11 -04:00
parent 95ec4bc4a1
commit 35177f448f
13 changed files with 243 additions and 12 deletions

View File

@@ -33,6 +33,7 @@ interface TaskDetailModalProps {
onMoveTask: (id: string, column: Column) => Promise<Task>;
onDeleteTask: (id: string) => Promise<Task>;
onMergeTask: (id: string) => Promise<MergeResult>;
onRetryTask?: (id: string) => Promise<Task>;
addToast: (message: string, type?: ToastType) => void;
}
@@ -42,6 +43,7 @@ export function TaskDetailModal({
onMoveTask,
onDeleteTask,
onMergeTask,
onRetryTask,
addToast,
}: TaskDetailModalProps) {
const [attachments, setAttachments] = useState<TaskAttachment[]>(task.attachments || []);
@@ -102,6 +104,17 @@ export function TaskDetailModal({
});
}, [task.id, onMergeTask, onClose, addToast]);
const handleRetry = useCallback(async () => {
if (!onRetryTask) return;
try {
await onRetryTask(task.id);
onClose();
addToast(`Retrying ${task.id}...`, "info");
} catch (err: any) {
addToast(err.message, "error");
}
}, [task.id, onRetryTask, onClose, addToast]);
const handleUpload = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
@@ -270,6 +283,11 @@ export function TaskDetailModal({
<button className="btn btn-danger btn-sm" onClick={handleDelete}>
Delete
</button>
{task.status === "failed" && onRetryTask && (
<button className="btn btn-warning btn-sm" onClick={handleRetry}>
Retry
</button>
)}
<div style={{ flex: 1 }} />
{task.column === "in-review" ? (
<>