- Scaffold Next.js 15 app with TypeScript, Tailwind, App Router - Install @xyflow/react, Zustand, Lucide icons, nanoid - Define council types (AgentNodeData, CouncilBlueprint, WSMessage, etc.) - Implement Zustand store for canvas and run state - Build custom AgentNode component (label, system prompt, model badge, tool chips, active pulse) - Build ConditionalEdge component (dashed indigo line with condition label) - Build NodeSidebar (drag-and-drop + click to add agents) - Build NodeSettingsPanel (name, system prompt, model selector, tool toggles) - Build ArchitectCanvas (React Flow canvas with drop zone, minimap, controls) - Build blueprint parser (React Flow JSON ↔ CouncilBlueprint JSON) - Build API client for FastAPI backend (CRUD + run endpoints) - Build useCouncilWebSocket hook for live agent status via WebSocket - Build Tab A: Rat-Architekt (canvas builder with save/export toolbar) - Build Tab B: Konferenzzimmer (execution view with live diagram + result panel) - Add NavTabs navigation with CouncilOS branding - All TypeScript checks passing https://claude.ai/code/session_01EkbecUVn7esdxLCXxVVRDX
62 lines
2.3 KiB
TypeScript
62 lines
2.3 KiB
TypeScript
"use client";
|
|
|
|
import { useCallback } from "react";
|
|
import { Bot, Plus } from "lucide-react";
|
|
import { useCouncilStore } from "@/app/store/council-store";
|
|
|
|
// Sidebar panel — drag or click to add agent nodes to the canvas
|
|
export function NodeSidebar() {
|
|
const addAgentNode = useCouncilStore((s) => s.addAgentNode);
|
|
|
|
const onDragStart = useCallback(
|
|
(event: React.DragEvent<HTMLDivElement>) => {
|
|
event.dataTransfer.setData("application/reactflow", "agentNode");
|
|
event.dataTransfer.effectAllowed = "move";
|
|
},
|
|
[]
|
|
);
|
|
|
|
const handleAddClick = useCallback(() => {
|
|
// Add node at a reasonable default position near the center
|
|
addAgentNode({ x: 200 + Math.random() * 200, y: 100 + Math.random() * 200 });
|
|
}, [addAgentNode]);
|
|
|
|
return (
|
|
<aside className="w-52 flex-shrink-0 bg-white border-r border-slate-200 p-4 flex flex-col gap-4">
|
|
<h2 className="text-xs font-semibold text-slate-400 uppercase tracking-wider">
|
|
Komponenten
|
|
</h2>
|
|
|
|
{/* Draggable node template */}
|
|
<div
|
|
draggable
|
|
onDragStart={onDragStart}
|
|
onClick={handleAddClick}
|
|
className="flex items-center gap-2 rounded-lg border-2 border-dashed border-indigo-300 bg-indigo-50 px-3 py-3 cursor-grab active:cursor-grabbing hover:border-indigo-500 hover:bg-indigo-100 transition-colors select-none"
|
|
title="Auf Canvas ziehen oder klicken"
|
|
>
|
|
<Bot size={18} className="text-indigo-600" />
|
|
<span className="text-sm font-medium text-indigo-700">Agent</span>
|
|
<Plus size={14} className="text-indigo-400 ml-auto" />
|
|
</div>
|
|
|
|
<p className="text-xs text-slate-400 leading-snug">
|
|
Ziehe einen Agent auf die Zeichenfläche oder klicke, um ihn hinzuzufügen.
|
|
</p>
|
|
|
|
<div className="mt-auto space-y-1">
|
|
<p className="text-xs font-semibold text-slate-400 uppercase tracking-wider">
|
|
Kanten
|
|
</p>
|
|
<div className="flex items-center gap-2 text-xs text-slate-500">
|
|
<span className="block w-6 border-t-2 border-slate-400" />
|
|
Linear
|
|
</div>
|
|
<div className="flex items-center gap-2 text-xs text-slate-500">
|
|
<span className="block w-6 border-t-2 border-dashed border-indigo-500" />
|
|
Bedingt
|
|
</div>
|
|
</div>
|
|
</aside>
|
|
);
|
|
}
|