import { useRuntimeManager } from "../useRuntimeManager"; import { getRuntimeHealthSummary, getRuntimeWorkspaceSummary } from "../runtime-utils"; import type { RuntimeConfig, RuntimeDraftFieldKey, RuntimeDraftFieldMeta, RuntimeDraftFieldState, RuntimeSnapshot, RuntimeWorkspaceHealth, RuntimeWorkspaceSummary } from "../types"; import "./RuntimeWorkspace.css"; interface ExternalRuntimeProps { snapshot: RuntimeSnapshot; savedBaseline: RuntimeConfig; draftConfig: RuntimeConfig; draftDirty: boolean; draftOpen?: boolean; draftFields: RuntimeDraftFieldState; loading?: boolean; busy?: boolean; activeLifecycleCommand?: RuntimeSnapshot["active_command"]; lastLifecycleResult?: RuntimeSnapshot["last_command_result"]; lifecycleBusy?: boolean; applyImpact?: "immediate" | "restart_required" | "save_before_apply"; openDraft?: () => void; closeDraft?: () => void; resetDraft?: () => void; updateDraft?: (patch: Partial) => void; updateDraftField?: (field: K, value: RuntimeConfig[K]) => void; updateDraftFieldMeta?: (field: RuntimeDraftFieldKey, patch: Partial) => void; saveConfig?: (patch: Partial) => Promise; startLocal?: () => Promise; stopLocal?: () => Promise; } interface Props { runtime?: ExternalRuntimeProps; } function summarizePath(path: string | null): string { if (!path) return "No model selected"; const segments = path.split(/[\\/]/).filter(Boolean); return segments[segments.length - 1] || path; } function getLifecycleActionLabel(command: string): string | null { switch (command) { case "start": return "Starting local API..."; case "stop": return "Stopping local API..."; case "save": return "Saving changes..."; case "save_and_start": return "Saving and starting local API..."; default: return null; } } export default function RuntimeWorkspace({ runtime: externalRuntime }: Props) { const internalManager = useRuntimeManager(); // Use external runtime props if provided, otherwise use internal manager const useExternal = !!externalRuntime; const runtime = useExternal ? externalRuntime : internalManager; // Compute workspace summary and health from snapshot when using external props const workspaceSummary: RuntimeWorkspaceSummary = useExternal ? getRuntimeWorkspaceSummary(runtime.snapshot) : internalManager.workspaceSummary; const workspaceHealth: RuntimeWorkspaceHealth = useExternal ? getRuntimeHealthSummary(runtime.snapshot) : internalManager.workspaceHealth; const { draftDirty, draftConfig, savedBaseline, draftFields, applyImpact, busy, activeLifecycleCommand, lastLifecycleResult, lifecycleBusy, loading, openDraft, closeDraft, resetDraft, updateDraft, updateDraftField, updateDraftFieldMeta, saveConfig, startLocal, stopLocal, snapshot, } = runtime; const isLocal = snapshot.config.connection_mode === "local"; const lifecycleResult = lastLifecycleResult ?? { command: "idle" as const, outcome: "succeeded" as const, message: "" }; const showLifecycleResult = lifecycleResult.command !== "idle" && !lifecycleBusy; const lifecycleLabel = getLifecycleActionLabel(activeLifecycleCommand ?? ""); const hasInvalidDraft = Object.values(draftFields).some((meta) => meta?.invalid); const hasPendingDraft = Object.values(draftFields).some((meta) => meta?.pending); const hasBlockingDraftState = hasInvalidDraft || hasPendingDraft; const hasPendingModeChange = draftConfig.connection_mode !== savedBaseline.connection_mode; const restartRequiredWhileRunning = draftDirty && draftConfig.connection_mode === "local" && snapshot.process_running && applyImpact === "restart_required"; const applyGuidance = !draftDirty || draftConfig.connection_mode !== "local" ? null : hasPendingModeChange || applyImpact === "save_before_apply" ? "Stop the local API or save first before applying this change." : applyImpact === "restart_required" ? "Restart required to apply saved changes." : "Applies immediately after save."; const lifecycleResultClass = lifecycleResult.outcome === "failed" ? "runtime-workspace-result-danger" : lifecycleResult.outcome === "blocked" ? "runtime-workspace-result-warning" : "runtime-workspace-result-success"; const healthToneClass = `runtime-workspace-health-${workspaceHealth.tone}`; const saveLabel = activeLifecycleCommand === "save" ? "Saving changes..." : "Save changes"; const tertiaryLabel = hasPendingModeChange ? "Save mode before applying" : activeLifecycleCommand === "start" ? "Starting local API..." : activeLifecycleCommand === "stop" ? "Stopping local API..." : restartRequiredWhileRunning ? "Restart required to apply saved changes" : snapshot.process_running ? "Stop local API" : "Save and start local API"; if (loading) { return (
Loading runtime...
); } return (
{/* Header / Summary Section */}
Runtime workspace
{workspaceSummary.modeLabel === "local" ? "Local" : "Remote"}
{workspaceSummary.statusLabel}
{/* Health Section */}
Runtime health
{workspaceHealth.headline}
{workspaceHealth.detail &&
{workspaceHealth.detail}
}
{/* Connection Details */}
Endpoint {workspaceSummary.endpointLabel || "Not configured"}
Model {workspaceSummary.modelLabel || "No model selected"}
{isLocal && (
Start policy {snapshot.config.start_policy === "on_app_launch" ? "Auto-start" : "Manual"}
)}
{/* Lifecycle Result Banner */} {showLifecycleResult && (
{lifecycleResult.message}
)} {/* Actions */}
{isLocal && ( <> )}
{/* Draft Settings (inline when open) */} {draftDirty && (
Draft settings Unsaved changes
{/* Apply Guidance */} {applyGuidance && (
{applyGuidance}
)} {/* Local mode draft fields */} {draftConfig.connection_mode === "local" && updateDraft && ( <>
updateDraft({ models_dir: e.target.value })} placeholder="D:/models" />
updateDraft({ model_path: e.target.value || null })} placeholder="D:/models/model.gguf" />
updateDraft({ gpu_layers: parseInt(e.target.value, 10) || 0 })} />
)} {/* Remote mode draft fields */} {draftConfig.connection_mode === "remote" && updateDraft && ( <>
updateDraft({ server_url: e.target.value })} placeholder="https://api.example.com" />
updateDraft({ api_key: e.target.value })} placeholder="sk-..." />
)} {/* Draft Actions */} {updateDraft && resetDraft && (
)}
)}
); }