"use client"; import { useState, useEffect, useCallback } from "react"; import { Card, Button } from "@/shared/components"; interface ToolState { tool: string; installedVersion: string | null; currentVersion: string | null; status: string; pid: number | null; port: number; healthStatus: string; autoUpdate: boolean; autoStart: boolean; lastHealthCheck: string | null; errorMessage: string | null; } interface UpdateInfo { current: string | null; latest: string; updateAvailable: boolean; } export default function CliproxyapiToolCard({ isExpanded = false, onToggle = () => {} }) { const [toolState, setToolState] = useState(null); const [updateInfo, setUpdateInfo] = useState(null); const [loading, setLoading] = useState(null); const [message, setMessage] = useState<{ type: string; text: string } | null>(null); const fetchStatus = useCallback(async () => { try { const res = await fetch("/api/version-manager/status"); if (!res.ok) return; const data = await res.json(); const entry = Array.isArray(data) ? data.find((t: ToolState) => t.tool === "cliproxyapi") : null; setToolState(entry || null); } catch (err) { console.error("Failed to fetch CLIProxyAPI status:", err); } }, []); const fetchUpdateInfo = useCallback(async () => { try { const res = await fetch("/api/version-manager/check-update?tool=cliproxyapi"); if (!res.ok) return; setUpdateInfo(await res.json()); } catch (err) { console.error("Failed to fetch CLIProxyAPI update info:", err); } }, []); useEffect(() => { if (isExpanded) { fetchStatus(); fetchUpdateInfo(); } }, [isExpanded, fetchStatus, fetchUpdateInfo]); const apiCall = async (action: string, body?: Record) => { setLoading(action); setMessage(null); try { const res = await fetch(`/api/version-manager/${action}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ tool: "cliproxyapi", ...body }), }); const data = await res.json(); if (res.ok) { setMessage({ type: "success", text: data.message || `${action} succeeded` }); await fetchStatus(); if (action === "install" || action === "restart") await fetchUpdateInfo(); } else { setMessage({ type: "error", text: (typeof data.error === "string" ? data.error : data.error?.message) || `${action} failed`, }); } } catch (err) { setMessage({ type: "error", text: err instanceof Error ? err.message : "Request failed" }); } finally { setLoading(null); } }; const statusBadge = () => { if (!toolState) return null; const s = toolState.status; const map: Record = { running: { label: "Running", color: "bg-green-500/10 text-green-600 dark:text-green-400" }, stopped: { label: "Stopped", color: "bg-zinc-500/10 text-zinc-500 dark:text-zinc-400" }, not_installed: { label: "Not Installed", color: "bg-yellow-500/10 text-yellow-600 dark:text-yellow-400", }, installed: { label: "Installed", color: "bg-blue-500/10 text-blue-600 dark:text-blue-400" }, error: { label: "Error", color: "bg-red-500/10 text-red-600 dark:text-red-400" }, }; const badge = map[s] || map.not_installed; return ( {badge.label} ); }; return (
swap_horiz

CLIProxyAPI

{statusBadge()}

Upstream proxy fallback (Go-based OAuth)

expand_more
{isExpanded && (
{message && (
{message.type === "success" ? "check_circle" : "error"} {message.text}
)} {updateInfo?.updateAvailable && (
system_update Update available: v{updateInfo.current} → v{updateInfo.latest}
)}

Version

{toolState?.installedVersion ? `v${toolState.installedVersion}` : "Not installed"}

Health

{toolState?.healthStatus === "healthy" ? `Healthy` : toolState?.healthStatus === "unhealthy" ? "Unhealthy" : "Unknown"}

Port

{toolState?.port || 8317}

{!toolState?.installedVersion && ( )} {toolState?.status === "running" ? ( ) : toolState?.installedVersion ? ( ) : null} {toolState?.status === "running" && ( )}
)}
); }