import { useState } from "react" import { FileCheck, FlaskConical, Hammer, Loader2, ShieldCheck, Sparkles, type LucideIcon, } from "lucide-react" import { useProgramAction } from "@/services/api/hooks" interface ActionConfig { icon: LucideIcon label: string color: string hoverBg: string borderColor: string } // Dev verbs only — operations on the program's *source*. Deployment lifecycle // (install/uninstall a tool, start/stop a service, …) belongs to the deployment, // not the program, so it lives in the Deployment section, never here. const ACTION_CONFIG: Record = { build: { icon: Hammer, label: "Build", color: "text-blue-400", hoverBg: "hover:bg-blue-800/30", borderColor: "border-blue-800" }, test: { icon: FlaskConical, label: "Test", color: "text-purple-400", hoverBg: "hover:bg-purple-800/30", borderColor: "border-purple-800" }, lint: { icon: Sparkles, label: "Lint", color: "text-amber-400", hoverBg: "hover:bg-amber-800/30", borderColor: "border-amber-800" }, "type-check": { icon: FileCheck, label: "Type Check", color: "text-cyan-400", hoverBg: "hover:bg-cyan-800/30", borderColor: "border-cyan-800" }, check: { icon: ShieldCheck, label: "Check All", color: "text-green-400", hoverBg: "hover:bg-green-800/30", borderColor: "border-green-800" }, } const DEV_ACTIONS = ["build", "test", "lint", "type-check", "check"] export interface ActionOutput { action: string text: string ok: boolean } interface ProgramActionsProps { name: string actions: string[] compact?: boolean onOutput?: (output: ActionOutput) => void } export function ProgramActions({ name, actions, compact, onOutput, }: ProgramActionsProps) { const { mutate, isPending } = useProgramAction() const [runningAction, setRunningAction] = useState(null) const visible = DEV_ACTIONS.filter((a) => actions.includes(a)) const handleAction = (action: string) => { setRunningAction(action) onOutput?.({ action: "", text: "", ok: true }) // clear previous mutate( { name, action }, { onSuccess: (data) => { setRunningAction(null) if (!compact && data.output) { onOutput?.({ action, text: data.output, ok: true }) } }, onError: (err) => { setRunningAction(null) if (!compact) { let text = String(err) try { const parsed = JSON.parse((err as Error).message) text = parsed.detail ?? text } catch { text = (err as Error).message ?? text } onOutput?.({ action, text, ok: false }) } }, }, ) } if (visible.length === 0) return null return (
{visible.map((action) => { const config = ACTION_CONFIG[action] if (!config) return null const Icon = config.icon const isRunning = isPending && runningAction === action if (compact) { return ( ) } return ( ) })}
) } export function ActionOutputPanel({ output, onDismiss }: { output: ActionOutput; onDismiss: () => void }) { if (!output.action) return null return (
{ACTION_CONFIG[output.action]?.label ?? output.action} — {output.ok ? "ok" : "error"}
        {output.text}
      
) }