diff options
Diffstat (limited to 'makima/frontend/src/components/directives/DirectiveContractsTab.tsx')
| -rw-r--r-- | makima/frontend/src/components/directives/DirectiveContractsTab.tsx | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/makima/frontend/src/components/directives/DirectiveContractsTab.tsx b/makima/frontend/src/components/directives/DirectiveContractsTab.tsx new file mode 100644 index 0000000..59ebfc8 --- /dev/null +++ b/makima/frontend/src/components/directives/DirectiveContractsTab.tsx @@ -0,0 +1,131 @@ +import { useNavigate } from "react-router"; +import type { + DirectiveWithChains, + StepContractSummary, + ContractPhase, +} from "../../lib/api"; +import { PhaseProgressBarCompact } from "../contracts/PhaseProgressBar"; + +interface DirectiveContractsTabProps { + directive: DirectiveWithChains; +} + +const statusColors: Record<string, string> = { + active: "text-green-400", + completed: "text-blue-400", + archived: "text-[#555]", +}; + +function ContractCard({ + summary, + label, +}: { + summary: StepContractSummary; + label: string; +}) { + const navigate = useNavigate(); + + const progressPct = + summary.taskCount > 0 + ? Math.round((summary.tasksDone / summary.taskCount) * 100) + : 0; + + return ( + <div + className="border border-dashed border-[rgba(117,170,252,0.25)] bg-[rgba(117,170,252,0.03)] p-3 cursor-pointer hover:bg-[rgba(117,170,252,0.06)] transition-colors" + onClick={() => navigate(`/contracts/${summary.id}`)} + > + <div className="flex items-center justify-between mb-1.5"> + <div className="flex items-center gap-2 min-w-0"> + <span className="font-mono text-[11px] text-[#dbe7ff] truncate"> + {summary.name} + </span> + <span className="font-mono text-[9px] text-[#7788aa] uppercase shrink-0"> + {summary.contractType} + </span> + </div> + <div className="flex items-center gap-2 shrink-0"> + <span + className={`font-mono text-[9px] uppercase ${statusColors[summary.status] || "text-[#888]"}`} + > + {summary.status} + </span> + <span className="font-mono text-[9px] text-[#75aafc]">→</span> + </div> + </div> + + <div className="flex items-center gap-2 mb-1.5"> + <span className="font-mono text-[9px] text-[#7788aa] uppercase shrink-0"> + {label} + </span> + <PhaseProgressBarCompact + currentPhase={summary.phase as ContractPhase} + /> + </div> + + {/* Task progress bar */} + <div className="flex items-center gap-2"> + <div className="flex-1 h-1 bg-[rgba(117,170,252,0.1)] rounded-full overflow-hidden"> + <div + className="h-full bg-[#3f6fb3] rounded-full transition-all" + style={{ width: `${progressPct}%` }} + /> + </div> + <span className="font-mono text-[9px] text-[#7788aa] shrink-0"> + {summary.tasksDone}/{summary.taskCount} tasks + </span> + </div> + </div> + ); +} + +export function DirectiveContractsTab({ + directive, +}: DirectiveContractsTabProps) { + // Collect all contract summaries + const contracts: { summary: StepContractSummary; label: string }[] = []; + + if (directive.orchestratorContractSummary) { + contracts.push({ + summary: directive.orchestratorContractSummary, + label: "Planning", + }); + } + + for (const chain of directive.chains) { + for (const step of chain.steps) { + if (step.contractSummary) { + contracts.push({ + summary: step.contractSummary, + label: step.name, + }); + } + } + } + + if (contracts.length === 0) { + return ( + <div className="text-center py-8"> + <p className="font-mono text-xs text-[#7788aa]"> + {directive.status === "draft" + ? "No contracts yet. Start the directive to begin planning." + : directive.status === "planning" + ? "Planning in progress... contracts will appear when steps are created." + : "No contracts associated with this directive."} + </p> + </div> + ); + } + + return ( + <div className="space-y-2"> + {contracts.map((c) => ( + <ContractCard + key={c.summary.id} + summary={c.summary} + label={c.label} + /> + ))} + </div> + ); +} |
