From 1b692b8cde4a888c8a35af69231f181b57bf5619 Mon Sep 17 00:00:00 2001 From: soryu Date: Fri, 6 Feb 2026 20:06:30 +0000 Subject: Fix: Cleanup old chain code --- .../src/components/directives/ApprovalsTab.tsx | 77 ++++++++ .../src/components/directives/ChainTab.tsx | 212 +++++++++++++++++++++ .../components/directives/CreateDirectiveModal.tsx | 146 ++++++++++++++ .../src/components/directives/DirectiveDetail.tsx | 160 ++++++++++++++++ .../src/components/directives/DirectiveList.tsx | 85 +++++++++ .../components/directives/DirectiveListItem.tsx | 83 ++++++++ .../src/components/directives/EvaluationsTab.tsx | 12 ++ .../src/components/directives/EventsTab.tsx | 77 ++++++++ .../src/components/directives/OverviewTab.tsx | 73 +++++++ .../src/components/directives/StepNode.tsx | 87 +++++++++ .../src/components/directives/VerifiersTab.tsx | 12 ++ makima/frontend/src/components/directives/index.ts | 11 ++ 12 files changed, 1035 insertions(+) create mode 100644 makima/frontend/src/components/directives/ApprovalsTab.tsx create mode 100644 makima/frontend/src/components/directives/ChainTab.tsx create mode 100644 makima/frontend/src/components/directives/CreateDirectiveModal.tsx create mode 100644 makima/frontend/src/components/directives/DirectiveDetail.tsx create mode 100644 makima/frontend/src/components/directives/DirectiveList.tsx create mode 100644 makima/frontend/src/components/directives/DirectiveListItem.tsx create mode 100644 makima/frontend/src/components/directives/EvaluationsTab.tsx create mode 100644 makima/frontend/src/components/directives/EventsTab.tsx create mode 100644 makima/frontend/src/components/directives/OverviewTab.tsx create mode 100644 makima/frontend/src/components/directives/StepNode.tsx create mode 100644 makima/frontend/src/components/directives/VerifiersTab.tsx create mode 100644 makima/frontend/src/components/directives/index.ts (limited to 'makima/frontend/src/components') diff --git a/makima/frontend/src/components/directives/ApprovalsTab.tsx b/makima/frontend/src/components/directives/ApprovalsTab.tsx new file mode 100644 index 0000000..dca48df --- /dev/null +++ b/makima/frontend/src/components/directives/ApprovalsTab.tsx @@ -0,0 +1,77 @@ +import type { DirectiveWithProgress } from "../../lib/api"; + +export function ApprovalsTab({ directive, onRefresh }: { directive: DirectiveWithProgress; onRefresh: () => void }) { + if (directive.pendingApprovals.length === 0) { + return ( +
+

No pending approvals

+
+ ); + } + + const handleApprove = async (approvalId: string) => { + try { + const { approveDirectiveRequest } = await import("../../lib/api"); + await approveDirectiveRequest(directive.id, approvalId); + onRefresh(); + } catch (err) { + console.error("Failed to approve:", err); + } + }; + + const handleDeny = async (approvalId: string) => { + try { + const { denyDirectiveRequest } = await import("../../lib/api"); + await denyDirectiveRequest(directive.id, approvalId); + onRefresh(); + } catch (err) { + console.error("Failed to deny:", err); + } + }; + + return ( +
+ {directive.pendingApprovals.map((approval) => { + const urgencyColor = { + low: "text-[#556677]", + normal: "text-[#75aafc]", + high: "text-yellow-400", + critical: "text-red-400", + }[approval.urgency] || "text-[#556677]"; + + return ( +
+
+
+
+ {approval.approvalType} + + {approval.urgency} + +
+

{approval.description}

+
+
+ + +
+
+
+ ); + })} +
+ ); +} diff --git a/makima/frontend/src/components/directives/ChainTab.tsx b/makima/frontend/src/components/directives/ChainTab.tsx new file mode 100644 index 0000000..ccefe81 --- /dev/null +++ b/makima/frontend/src/components/directives/ChainTab.tsx @@ -0,0 +1,212 @@ +import { useState, useMemo } from "react"; +import { + ReactFlow, + Edge, + Controls, + Background, + BackgroundVariant, + MarkerType, +} from "@xyflow/react"; +import "@xyflow/react/dist/style.css"; +import type { DirectiveWithProgress, DirectiveGraphResponse } from "../../lib/api"; +import { StepNodeComponent, stepStatusStyles } from "./StepNode"; + +// Node types for React Flow +const nodeTypes = { + step: StepNodeComponent, +}; + +export function ChainTab({ directive, graph }: { directive: DirectiveWithProgress; graph: DirectiveGraphResponse | null }) { + const [viewMode, setViewMode] = useState<"dag" | "list">("dag"); + + // Convert graph to React Flow nodes and edges + const { nodes, edges } = useMemo(() => { + if (!graph || !graph.nodes.length) { + // Fallback: generate positions from directive.steps + const stepNodes = directive.steps.map((step, index) => ({ + id: step.id, + type: "step" as const, + position: { + x: (index % 3) * 220 + 50, + y: Math.floor(index / 3) * 120 + 50, + }, + data: { + id: step.id, + name: step.name, + stepType: step.stepType, + status: step.status, + confidenceScore: step.confidenceScore, + confidenceLevel: step.confidenceLevel, + contractId: step.contractId, + editorX: null, + editorY: null, + }, + })); + + // Build edges from dependencies + const stepEdges: Edge[] = []; + directive.steps.forEach((step) => { + (step.dependsOn ?? []).forEach((depName) => { + const depStep = directive.steps.find((s) => s.name === depName); + if (depStep) { + stepEdges.push({ + id: `${depStep.id}-${step.id}`, + source: depStep.id, + target: step.id, + type: "smoothstep", + markerEnd: { type: MarkerType.ArrowClosed, color: "#556677" }, + style: { stroke: "#556677", strokeWidth: 2 }, + }); + } + }); + }); + + return { nodes: stepNodes, edges: stepEdges }; + } + + // Use graph data + const graphNodes = graph.nodes.map((node) => ({ + id: node.id, + type: "step" as const, + position: { + x: node.editorX ?? 50, + y: node.editorY ?? 50, + }, + data: { ...node }, + })); + + const graphEdges: Edge[] = graph.edges.map((edge) => ({ + id: `${edge.source}-${edge.target}`, + source: edge.source, + target: edge.target, + type: "smoothstep", + markerEnd: { type: MarkerType.ArrowClosed, color: "#556677" }, + style: { stroke: "#556677", strokeWidth: 2 }, + })); + + return { nodes: graphNodes, edges: graphEdges }; + }, [graph, directive.steps]); + + if (!directive.chain) { + return ( +
+

+ No chain generated yet. Start the directive to generate a chain. +

+
+ ); + } + + return ( +
+ {/* Chain info header */} +
+
+
{directive.chain.name}
+
Generation {directive.chain.generation}
+
+
+
+ {directive.chain.completedSteps}/{directive.chain.totalSteps} steps +
+ {/* View toggle */} +
+ + +
+
+
+ + {viewMode === "dag" ? ( + /* DAG visualization */ +
+ {directive.steps.length === 0 ? ( +
+

No steps in chain

+
+ ) : ( + + + + + )} +
+ ) : ( + /* List view */ +
+

Steps

+ {directive.steps.length === 0 ? ( +

No steps in chain

+ ) : ( + directive.steps.map((step) => { + const styles = stepStatusStyles[step.status] || stepStatusStyles.pending; + + return ( +
+
+
+ {step.name} + + {step.status} + + {step.confidenceScore !== null && ( + + ({Math.round(step.confidenceScore * 100)}%) + + )} +
+
{step.stepType}
+
+ {step.description && ( +

{step.description}

+ )} + {step.dependsOn?.length > 0 && ( +
+ Depends on: {step.dependsOn.join(", ")} +
+ )} +
+ ); + }) + )} +
+ )} +
+ ); +} diff --git a/makima/frontend/src/components/directives/CreateDirectiveModal.tsx b/makima/frontend/src/components/directives/CreateDirectiveModal.tsx new file mode 100644 index 0000000..7f52a7e --- /dev/null +++ b/makima/frontend/src/components/directives/CreateDirectiveModal.tsx @@ -0,0 +1,146 @@ +import { useState, useEffect } from "react"; +import type { AutonomyLevel, RepositoryHistoryEntry } from "../../lib/api"; +import { getRepositorySuggestions } from "../../lib/api"; + +interface CreateDirectiveModalProps { + onSubmit: (goal: string, repositoryUrl: string | undefined, autonomyLevel: AutonomyLevel) => void; + onCancel: () => void; +} + +export function CreateDirectiveModal({ onSubmit, onCancel }: CreateDirectiveModalProps) { + const [goal, setGoal] = useState(""); + const [repositoryUrl, setRepositoryUrl] = useState(""); + const [autonomyLevel, setAutonomyLevel] = useState("guardrails"); + const [suggestions, setSuggestions] = useState([]); + const [showSuggestions, setShowSuggestions] = useState(false); + + // Load suggestions + useEffect(() => { + getRepositorySuggestions("remote", undefined, 5) + .then((res) => { + setSuggestions(res.entries); + }) + .catch(() => { + setSuggestions([]); + }); + }, []); + + const handleSubmit = () => { + if (goal.trim()) { + onSubmit(goal.trim(), repositoryUrl.trim() || undefined, autonomyLevel); + } + }; + + return ( +
+
+

+ Create Directive +

+ +
+ {/* Goal */} +
+ +