diff options
| author | soryu <soryu@soryu.co> | 2026-02-06 20:06:30 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-06 20:15:27 +0000 |
| commit | 1b692b8cde4a888c8a35af69231f181b57bf5619 (patch) | |
| tree | 74ce25ce6ee5fb4536b53404e1a0ae923e85c30d /makima/frontend/src/components/directives/DirectiveDetail.tsx | |
| parent | 139be135c2086d725e4f040e744bb25acd436549 (diff) | |
| download | soryu-1b692b8cde4a888c8a35af69231f181b57bf5619.tar.gz soryu-1b692b8cde4a888c8a35af69231f181b57bf5619.zip | |
Fix: Cleanup old chain code
Diffstat (limited to 'makima/frontend/src/components/directives/DirectiveDetail.tsx')
| -rw-r--r-- | makima/frontend/src/components/directives/DirectiveDetail.tsx | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/makima/frontend/src/components/directives/DirectiveDetail.tsx b/makima/frontend/src/components/directives/DirectiveDetail.tsx new file mode 100644 index 0000000..06b24bb --- /dev/null +++ b/makima/frontend/src/components/directives/DirectiveDetail.tsx @@ -0,0 +1,160 @@ +import { useState } from "react"; +import type { DirectiveWithProgress, DirectiveGraphResponse } from "../../lib/api"; +import { OverviewTab } from "./OverviewTab"; +import { ChainTab } from "./ChainTab"; +import { EventsTab } from "./EventsTab"; +import { EvaluationsTab } from "./EvaluationsTab"; +import { ApprovalsTab } from "./ApprovalsTab"; +import { VerifiersTab } from "./VerifiersTab"; + +interface DirectiveDetailProps { + directive: DirectiveWithProgress; + graph: DirectiveGraphResponse | null; + loading: boolean; + onBack: () => void; + onRefresh: () => void; + onStart: () => void; + onPause: () => void; + onResume: () => void; + onStop: () => void; +} + +export function DirectiveDetail({ + directive, + graph, + loading, + onBack, + onRefresh, + onStart, + onPause, + onResume, + onStop, +}: DirectiveDetailProps) { + const [activeTab, setActiveTab] = useState<"overview" | "chain" | "events" | "evaluations" | "approvals" | "verifiers">("overview"); + + if (loading) { + return ( + <div className="panel h-full flex items-center justify-center"> + <p className="font-mono text-xs text-[#556677]">Loading...</p> + </div> + ); + } + + const statusColor = { + draft: "text-[#556677] bg-[#556677]/10 border-[#556677]/30", + planning: "text-yellow-400 bg-yellow-400/10 border-yellow-400/30", + active: "text-green-400 bg-green-400/10 border-green-400/30", + paused: "text-yellow-400 bg-yellow-400/10 border-yellow-400/30", + completed: "text-[#75aafc] bg-[#75aafc]/10 border-[#75aafc]/30", + archived: "text-[#556677] bg-[#556677]/10 border-[#556677]/30", + failed: "text-red-400 bg-red-400/10 border-red-400/30", + }[directive.status] || "text-[#556677] bg-[#556677]/10 border-[#556677]/30"; + + return ( + <div className="panel h-full flex flex-col overflow-hidden"> + {/* Header */} + <div className="p-3 border-b border-[rgba(117,170,252,0.15)]"> + <div className="flex items-center justify-between"> + <div className="flex items-center gap-3"> + <button + onClick={onBack} + className="font-mono text-xs text-[#556677] hover:text-[#9bc3ff]" + > + ← Back + </button> + <h2 className="font-mono text-sm text-[#dbe7ff]"> + {directive.title || directive.goal.slice(0, 50)} + </h2> + <span className={`px-2 py-0.5 font-mono text-[10px] uppercase border ${statusColor}`}> + {directive.status} + </span> + </div> + <div className="flex items-center gap-2"> + {directive.status === "draft" && ( + <button + onClick={onStart} + className="px-3 py-1 font-mono text-[10px] text-[#dbe7ff] bg-green-700 border border-green-600 hover:bg-green-600 uppercase" + > + Start + </button> + )} + {directive.status === "active" && ( + <button + onClick={onPause} + className="px-3 py-1 font-mono text-[10px] text-[#dbe7ff] bg-yellow-700 border border-yellow-600 hover:bg-yellow-600 uppercase" + > + Pause + </button> + )} + {directive.status === "paused" && ( + <button + onClick={onResume} + className="px-3 py-1 font-mono text-[10px] text-[#dbe7ff] bg-green-700 border border-green-600 hover:bg-green-600 uppercase" + > + Resume + </button> + )} + {["active", "paused"].includes(directive.status) && ( + <button + onClick={onStop} + className="px-3 py-1 font-mono text-[10px] text-[#dbe7ff] bg-red-700 border border-red-600 hover:bg-red-600 uppercase" + > + Stop + </button> + )} + <button + onClick={onRefresh} + className="px-3 py-1 font-mono text-[10px] text-[#9bc3ff] hover:text-[#dbe7ff]" + > + Refresh + </button> + </div> + </div> + </div> + + {/* Tabs */} + <div className="flex gap-1 p-2 border-b border-[rgba(117,170,252,0.1)]"> + {(["overview", "chain", "events", "evaluations", "approvals", "verifiers"] as const).map((tab) => ( + <button + key={tab} + onClick={() => setActiveTab(tab)} + className={`px-3 py-1.5 font-mono text-[10px] uppercase ${ + activeTab === tab + ? "text-[#dbe7ff] bg-[#0f3c78] border border-[#3f6fb3]" + : "text-[#556677] hover:text-[#9bc3ff]" + }`} + > + {tab} + {tab === "approvals" && directive.pendingApprovals.length > 0 && ( + <span className="ml-1 px-1 bg-yellow-500 text-black rounded text-[8px]"> + {directive.pendingApprovals.length} + </span> + )} + </button> + ))} + </div> + + {/* Tab Content */} + <div className="flex-1 overflow-y-auto p-4"> + {activeTab === "overview" && ( + <OverviewTab directive={directive} /> + )} + {activeTab === "chain" && ( + <ChainTab directive={directive} graph={graph} /> + )} + {activeTab === "events" && ( + <EventsTab directive={directive} /> + )} + {activeTab === "evaluations" && ( + <EvaluationsTab directive={directive} /> + )} + {activeTab === "approvals" && ( + <ApprovalsTab directive={directive} onRefresh={onRefresh} /> + )} + {activeTab === "verifiers" && ( + <VerifiersTab directive={directive} /> + )} + </div> + </div> + ); +} |
