Intelligence
Artifacts
Browse the repository, read documents, and manage the governance folders. Source, runtime, and infrastructure are read-only.
Repository
assignment-dispatch-button.tsxassignment-status-badge.tsxassignments-panel.tsxcreate-mission-form.tsxgovernance-panels.tsxmission-dispatch.tsxmission-edit.tsxmission-state-actions.tsxmission-status-badge.tsxobjective-edit.tsxobjective-status-badge.tsxobjective-status-select.tsxobjectives-panel.tsxreport-list.tsxwork-orders-panel.tsx
README.md
CONSTITUTION_COMPLIANCE_AUDIT_V1.mdREADME.md
repositories/aaf-holdings/hq01/components/workers/worker-instantiate.tsx
2.6 KB
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { HardHat, Loader2, AlertTriangle } from "lucide-react";
import { Button } from "@/components/ui/button";
import type { AssignmentStatus } from "@/lib/missions/types";
export interface TemplateOption {
id: string;
name: string;
}
/**
* Instantiate a worker from a template for an assignment. The worker runs
* through the existing engine and terminates; no worker persists.
*/
export function WorkerInstantiate({
missionId,
aid,
templates,
status,
}: {
missionId: string;
aid: string;
templates: TemplateOption[];
status: AssignmentStatus;
}) {
const router = useRouter();
const [templateId, setTemplateId] = useState(templates[0]?.id ?? "");
const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null);
const canInstantiate = status === "Pending" || status === "Failed";
async function instantiate() {
setBusy(true);
setError(null);
try {
const res = await fetch(
`/api/missions/${missionId}/assignments/${aid}/workers`,
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ templateId }),
},
);
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(data.error ?? "Instantiation failed.");
router.refresh();
} catch (err) {
setError(err instanceof Error ? err.message : "Instantiation failed.");
setBusy(false);
}
}
if (!canInstantiate) {
return (
<span className="text-[12px] text-muted-foreground">
Worker already dispatched ({status.toLowerCase()}).
</span>
);
}
return (
<div className="flex flex-col items-end gap-1">
<div className="flex items-center gap-2">
<select
value={templateId}
onChange={(e) => setTemplateId(e.target.value)}
className="h-9 rounded-md border border-input bg-background px-2 text-sm"
>
{templates.map((t) => (
<option key={t.id} value={t.id}>
{t.name}
</option>
))}
</select>
<Button type="button" size="sm" onClick={instantiate} disabled={busy || !templateId}>
{busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <HardHat className="h-3.5 w-3.5" />}
Instantiate Worker
</Button>
</div>
{error && (
<span className="flex items-center gap-1 text-[11px] text-destructive">
<AlertTriangle className="h-3 w-3" /> {error}
</span>
)}
</div>
);
}
root · /srv/aaf