1import { r as reactExports, j as jsxRuntimeExports } from "./vendor-react-Bay9Y7Lb.js"; 2import { a as api } from "./index-D0Bmh-UX.js"; 3import { u as useIdlePollingPause } from "./useIdlePollingPause-Al1AXAz9.js"; 4import { b6 as LoaderCircle, cf as Activity, bL as Clock, ci as Cpu, cg as Gauge, bp as CirclePlay, bR as CircleStop, cL as RefreshCw, bv as CircleCheckBig, b1 as CircleAlert, ct as TrendingUp, bs as Zap, g9 as Workflow, bA as Eye, b5 as Trash2, eu as Terminal, ch as Database, e7 as CircleX, b2 as Upload, ga as RotateCw, cp as Settings2, cc as Save, er as Power, cQ as Minus, ce as Plus, dl as Scissors, b3 as FileHeadphone } from "./vendor-dVNaLJx_.js"; 5import "./vendor-i18n-R-bMoYp_.js"; 6const LogLine = ({ index, log }) => { 7 const isError = log.toLowerCase().includes("error"); 8 const timestampMatch = log.match(/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2},\d{3})/); 9 if (timestampMatch) { 10 const utcTimestamp = timestampMatch[1]; 11 const localDate = /* @__PURE__ */ new Date(utcTimestamp.replace(",", ".") + "Z"); 12 const localTimestamp = localDate.toLocaleTimeString(); 13 const message = log.substring(timestampMatch[0].length); 14 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `break-all whitespace-pre-wrap hover:bg-white/5 p-0.5 rounded transition-colors ${isError ? "text-red-500 dark:text-red-400" : ""}`, children: [
15 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "opacity-50 select-none mr-2", children: index + 1 }), 16 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `font-semibold mr-2 ${isError ? "text-red-600 dark:text-red-300" : "text-sky-400"}`, children: [ 17 "[", 18 localTimestamp, 19 "]" 20 ] }), 21 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: message }) 22 ] }); 23 } 24 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `break-all whitespace-pre-wrap hover:bg-white/5 p-0.5 rounded transition-colors ${isError ? "text-red-500 dark:text-red-400" : ""}`, children: [ 25 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "opacity-50 select-none mr-2", children: index + 1 }), 26 log 27 ] }); 28}; 29const PipelineCapabilities = ({ steps, enabledSteps, onToggle, error, onSelectAll, onSave, isSaving }) => { 30 const allSelected = steps.length > 0 && steps.every((s) => enabledSteps.includes(s.slug)); 31 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [ 32 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-4", children: [
33 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-lg font-bold text-zinc-900 dark:text-white flex items-center gap-2", children: [ 34 /* @__PURE__ */ jsxRuntimeExports.jsx(Workflow, { size: 20, className: "text-indigo-500" }), 35 " Pipeline Workflow" 36 ] }), 37 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 38 steps.length > 0 && !error && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 39 /* @__PURE__ */ jsxRuntimeExports.jsxs( 40 "button", 41 { 42 onClick: onSave, 43 disabled: isSaving, 44 className: "flex items-center gap-1.5 px-3 py-1 bg-indigo-600 hover:bg-indigo-700 text-white text-[10px] font-black uppercase rounded shadow-sm transition-all disabled:opacity-50", 45 children: [ 46 isSaving ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 12, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 12 }), 47 isSaving ? "Saving" : "Save Config" 48 ] 49 } 50 ),
51 /* @__PURE__ */ jsxRuntimeExports.jsx( 52 "button", 53 { 54 onClick: (e) => { 55 e.stopPropagation(); 56 onSelectAll == null ? void 0 : onSelectAll(); 57 }, 58 className: "text-[10px] font-black uppercase text-indigo-600 hover:text-indigo-700 bg-indigo-50 dark:bg-indigo-900/20 px-2 py-1 rounded transition-colors", 59 children: allSelected ? "Deselect All" : "Select All" 60 } 61 ) 62 ] }), 63 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] bg-zinc-100 dark:bg-zinc-800 px-2 py-1 rounded font-bold text-zinc-500 uppercase", children: error ? "Discovery Error" : "Discovery" }) 64 ] }) 65 ] }), 66 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-500 dark:text-zinc-400 mb-6", children: "The worker performs the following operations sequentially. Toggle steps to customize the MIDI processing pipeline." }), 67 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: error ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 py-8 px-4 text-center border-2 border-dashed border-red-100 dark:border-red-900/30 rounded-xl bg-red-50/50 dark:bg-red-900/10", children: [
68 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "mx-auto text-red-500 mb-2", size: 24 }), 69 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-red-600 dark:text-red-400 font-bold", children: error }), 70 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-400 mt-1 italic", children: "Check if worker/pipeline_steps.json exists in the repo root." }) 71 ] }) : steps.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "col-span-2 py-8 text-center border-2 border-dashed border-zinc-100 dark:border-zinc-800 rounded-xl", children: [ 72 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin mx-auto text-zinc-300", size: 24 }), 73 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 mt-2", children: "Discovering steps from worker manifest..." }) 74 ] }) : steps.map((step, index) => { 75 const isEnabled = enabledSteps.includes(step.slug); 76 const enabledBefore = steps.slice(0, index + 1).filter((s) => enabledSteps.includes(s.slug)).length; 77 const totalEnabled = steps.filter((s) => enabledSteps.includes(s.slug)).length; 78 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 79 "div", 80 { 81 onClick: () => onToggle(step.slug), 82 className: `flex items-start gap-3 p-3 rounded-lg border transition-all cursor-pointer group ${isEnabled ? "bg-indigo-50/50 dark:bg-indigo-900/10 border-indigo-200 dark:border-indigo-800" : "bg-zinc-50 dark:bg-zinc-800/20 border-zinc-100 dark:border-zinc-800 grayscale opacity-70"}`, 83 children: [
84 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `p-2 rounded-md border flex items-center justify-center transition-colors ${isEnabled ? "bg-white dark:bg-zinc-800 border-indigo-200 dark:border-indigo-700 text-indigo-500" : "bg-zinc-100 dark:bg-zinc-900 border-zinc-200 dark:border-zinc-800 text-zinc-400"}`, children: isEnabled ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-black", children: enabledBefore }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-4 h-4 rounded-full border-2 border-zinc-300 dark:border-zinc-700" }) }), 85 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [ 86 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-bold text-zinc-900 dark:text-white flex items-center justify-between", children: [ 87 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5", children: [ 88 step.name, 89 isEnabled && /* @__P
89URE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] text-zinc-400 font-normal", children: [ 90 "Step ", 91 enabledBefore, 92 "/", 93 totalEnabled 94 ] }) 95 ] }), 96 step.slug === "engrave_v15" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] bg-indigo-100 text-indigo-600 px-1 py-0.5 rounded", children: "V1.5" }) 97 ] }), 98 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 leading-tight mt-0.5 line-clamp-2", children: step.description }) 99 ] }) 100 ] 101 }, 102 step.slug 103 ); 104 }) }) 105 ] }); 106}; 107const SOURCE_COLORS = { 108 "Aria-MIDI": "bg-fuchsia-100 dark:bg-fuchsia-900/30 text-fuchsia-600 dark:text-fuchsia-400", 109 "User Upload": "bg-emerald-100 dark:bg-emerald-900/30 text-emerald-600 dark:text-emerald-400", 110 "Legacy": "bg-zinc-100 dark:bg-zinc-800 text-zinc-500 dark:text-zinc-400", 111 "lakh": "bg-sky-100 dark:bg-sky-900/30 text-sky-600 dark:text-sky-400", 112 "GiantMIDI": "bg-violet-100 dark:bg-violet-900/30 text-violet-600 dark:text-violet-400", 113 "MutopiaProject": "bg-lime-100 dark:bg-lime-900/30 text-lime-600 dark:text-lime-400", 114 "BitMidi": "bg-orange-100 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400" 115}; 116const formatCompact = (n) => { 117 if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`; 118 if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`; 119 return String(n); 120}; 121const SourcePills = ({ breakdown, withDivider }) => { 122 if (!breakdown || Object.keys(breakdown).length === 0) return null; 123 const entries = Object.entries(breakdown).sort((a, b) => b[1] - a[1]); 124 if (withDivider) { 125 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 pt-2 border-t border-zinc-100 dark:border-zinc-800", children: [
126 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[8px] font-bold text-zinc-400 uppercase mb-1", children: "Sources" }), 127 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1", children: entries.map(([source, count]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `text-[8px] font-black uppercase px-1 py-0.5 rounded ${SOURCE_COLORS[source] || "bg-zinc-100 dark:bg-zinc-800 text-zinc-500"}`, children: [ 128 source === "MutopiaProject" ? "Mutopia" : source, 129 " ", 130 formatCompact(count) 131 ] }, source)) }) 132 ] }); 133 } 134 return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1 mt-1.5", children: entries.map(([source, count]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `text-[8px] font-black uppercase px-1 py-0.5 rounded ${SOURCE_COLORS[source] || "bg-zinc-100 dark:bg-zinc-800 text-zinc-500"}`, children: [ 135 source === "MutopiaProject" ? "Mutopia" : source, 136 " ", 137 formatCompact(count) 138 ] }, source)) }); 139}; 140const calculateETC = (pending, processing, m10Rate, m30Rate) => { 141 if (pending === 0) return "0s"; 142 let ratePerHour = m10Rate; 143 if (ratePerHour === 0) ratePerHour = m30Rate; 144 if (ratePerHour === 0 && processing > 0) return "Calculating..."; 145 if (ratePerHour === 0 && processing === 0) return "Paused / Waiting for Workers"; 146 const totalHours = pending / ratePerHour; 147 const days = Math.floor(totalHours / 24); 148 const hours = Math.floor(totalHours % 24); 149 const minutes = Math.floor(totalHours * 60 % 60); 150 const seconds = Math.floor(totalHours * 3600 % 60); 151 let result = ""; 152 if (days > 0) result += `${days}d `; 153 if (hours > 0 || days > 0) result += `${hours}h `; 154 if (minutes > 0 || hours > 0 || days > 0) result += `${minutes}m `; 155 if (days === 0 && hours === 0) result += `${seconds}s`; 156 return result.trim(); 157}; 158const formatRam = (bytes) => { 159 if (!bytes) return "N/A"; 160 const gb = bytes / (1024 * 1024 * 1024); 161 return `${gb.toFixed(1)} GB`; 162}; 163const getNodeForInstance = (inst) => { 164 const pidStr = String(inst.pid); 165 if (pidStr.startsWith("hk_") || inst.elapsed && inst.elapsed.includes("Node 1")) { 166 return { id: 1, name: "Hong Kong Node" }; 167 } 168 if (pidStr.startsWith("gcp3_") || inst.elapsed && inst.elapsed.includes("Node 3")) { 169 return { id: 3, name: "GCP VM Node" }; 170 } 171 if (pidStr.startsWith("gcp4_") || inst.elapsed && inst.elapsed.includes("Node 4")) { 172 return { id: 4, name: "GCP Spot (Fast) Node" }; 173 } 174 if (pidStr.startsWith("gcp5_") || inst.elapsed && inst.elapsed.includes("Node 5")) { 175 return { id: 5, name: "GCP Spot (Queue Cleaver) Node" }; 176 } 177 return { id: 2, name: "Japan Node (Local)" }; 178}; 179const formatPidDisplay = (pid) => { 180 const pidStr = String(pid); 181 if (pidStr.startsWith("hk_")) { 182 return `HK: ${pidStr.substring(3)}`; 183 } 184 if (pidStr.startsWith("gcp3_")) { 185 return `GCP VM: ${pidStr.substring(5)}`; 186 } 187 if (pidStr.startsWith("gcp4_")) { 188 return `GCP Spot: ${pidStr.substring(5)}`; 189 } 190 if (pidStr.startsWith("gcp5_")) { 191 return `Node 5: ${pidStr.substring(5)}`; 192 } 193 return `Local PID: ${pidStr}`; 194}; 195const WorkerManager = () => { 196 var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y; 197 const [status, setStatus] = reactExports.useState({ pending: 0, processing: 0, completed: 0, metadataOnly: 0, rejected: 0, missing: 0, lastHeartbeat: null }); 198 const [isLoadingStatus, setIsLoadingStatus] = reactExports.useState(true); 199 const [lastRefreshedAt, setLastRefreshedAt] = reactExports.useState(null); 200 const { isPaused: isPollingPaused, isIdlePaused, setIsManualPaused: setIsPollingPaused } = useIdlePollingPause(); 201 const [workerNodes, setWorkerNodes] = reactExports.useState([]); 202 const [expandedWorkerConfig, setExpandedWorkerConfig] = reactExports.useState({}); 203 const [activeWorkerTasks, setActiveWorkerTasks] = reactExports.useState({}); 204 const [isLoadingNodes, setIsLoadingNodes] = reactExports.useState(false); 205 const [restartingNodes, setRestartingNodes] = reactExports.useState({}); 206 const [diagnosingNodes, setDiagnosingNodes] = reactExports.useState({}); 207 const [diagnosticReports, setDiagnosticReports] = reactExports.useState({}); 208 const [persistentErrors, setPersistentErrors] = reactExports.useState([]); 209 const [isLoadingErrors, setIsLoadingErrors] = reactExports.useState(false); 210 const [expandedErrorId, setExpandedErrorId] = reactExports.useState(null); 211 const [autoRefreshErrors, setAutoRefreshErrors] = reactExports.useState(false); 212 const [config, setConfig] = reactExports.useState({ enabled: true, poll_interval: 5, max_threads: 8, cpu_threshold: 80, enabledSteps: [] }); 213 const [pipelineSteps, setPipelineSteps] = reactExports.useState([]); 214 const [pipelineError, setPipelineError] = reactExports.useState(null); 215 const [isSaving, setIsSaving] = reactExports.useState(false); 216 const [overwriteFiles, setOverwriteFiles] = reactExports.useState(true); 217 const [logs, setLogs] = reactExports.useState([]);
218 const [loadingLogs, setLoadingLogs] = reactExports.useState(false); 219 const logContainerRef = reactExports.useRef(null); 220 const latestLogsRef = reactExports.useRef([]); 221 const [instances, setInstances] = reactExports.useState([]); 222 const [throughputStats, setThroughputStats] = reactExports.useState(null); 223 const [systemStats, setSystemStats] = reactExports.useState(null); 224 const [selectedInstance, setSelectedInstance] = reactExports.useState("unified"); 225 const [isSpawning, setIsSpawning] = reactExports.useState(false); 226 const [spawnCount, setSpawnCount] = reactExports.useState(1); 227 const [isClosingIdle, setIsClosingIdle] = reactExports.useState(false); 228 const [autoScroll, setAutoScroll] = reactExports.useState(true); 229 const [viewMode, setViewMode] = reactExports.useState("terminal"); 230 const [isRequeuingMissing, setIsRequeuingMissing] = reactExports.useState(false); 231 const [targetScale, setTargetScale] = reactExports.useState(1); 232 const [isScalingCluster, setIsScalingCluster] = reactExports.useState(false); 233 const isFirstScaleLoad = reactExports.useRef(true); 234 const [integrityResult, setIntegrityResult] = reactExports.useState(null); 235 const [isCheckingIntegrity, setIsCheckingIntegrity] = reactExports.useState(false); 236 const [selectedUnhealthyIds, setSelectedUnhealthyIds] = reactExports.useState([]); 237 const [integrityScanMode, setIntegrityScanMode] = reactExports.useState("idRange"); 238 const [integrityStartId, setIntegrityStartId] = reactExports.useState(""); 239 const [integrityEndId, setIntegrityEndId] = reactExports.useState(""); 240 const [integritySingleId, setIntegritySingleId] = reactExports.useState(""); 241 const [integrityStartDate, setIntegrityStartDate] = reactExports.useState(""); 242 const [integrityEndDate, setIntegrityEndDate] = reactExports.useState(""); 243 const [integrityDateField, setIntegrityDateField] = reactExports.useState("lastProcessedAt"); 244 const [integrityStatusFilter, setIntegrityStatusFilter] = reactExports.useState("completed"); 245 const [integrityMissingFile, setIntegrityMissingFile] = reactExports.useState("highOpus"); 246 const [integrityRequeueMissing, setIntegrityRequeueMissing] = reactExports.useState(true); 247 const [integrityTab, setIntegrityTab] = reactExports.useState("list"); 248 const [mapTracks, setMapTracks] = reactExports.useState([]); 249 const [selectedMapTrack, setSelectedMapTrack] = reactExports.useState(null); 250 const [mapSortMode, setMapSortMode] = reactExports.useState("sequential"); 251 const [isReprocessing, setIsReprocessing] = reactExports.useState(false); 252 const [bulkStartId, setBulkStartId] = reactExports.useState(""); 253 const [bulkEndId, setBulkEndId] = reactExports.useState(""); 254 const [bulkFullProcess, setBulkFullProcess] = reactExports.useState(true); 255 const [bulkSteps, setBulkSteps] = reactExports.useState([]); 256 const [isBulkProcessing, setIsBulkProcessing] = reactExports.useState(false); 257 const [bulkSkipCompleted, setBulkSkipCompleted] = reactExports.useState("both"); 258 const [replaceMidiId, setReplaceMidiId] = reactExports.useState(""); 259 const [replaceMidiFile, setReplaceMidiFile] = reactExports.useState(null); 260 const [isReplacingMidi, setIsReplacingMidi] = reactExports.useState(false); 261 const midiFileInputRef = reactExports.useRef(null); 262 const [priorityMidiId, setPriorityMidiId] = reactExports.useState(""); 263 const [isPrioritizing, setIsPrioritizing] = reactExports.useState(false); 264 const [converterLifetimeHours, setConverterLifetimeHours] = reactExports.useState(12); 265 const [isSavingConverterConfig, setIsSavingConverterConfig] = reactExports.useState(false); 266 const [isConfigured, setIsConfigured] = reactExports.useState(false); 267 const [backfillStats, setBackfillStats] = reactExports.useState(null); 268 const [backfillError, setBackfillError] = reactExports.useState(null); 269 const isFetchingBackfillRef = reactExports.useRef(false); 270 const [requeueMissingStatus, setRequeueMissingStatus] = reactExports.useState(null); 271 const fetchRequeueMissingStatus = reactExports.useCallback(async () => { 272 try { 273 const data = await api.getRequeueMissingStatus(); 274 setRequeueMissingStatus(data); 275 if (!data.isRunning && data.processedCount > 0 && (requeueMissingStatus == null ? void 0 : requeueMissingStatus.isRunning)) {
276 alert(`Background requeue finished. Scanned: ${data.processedCount}, Found & Requeued: ${data.foundCount}`); 277 refresh(); 278 } 279 } catch (e) { 280 console.error("Failed to fetch requeue missing status", e); 281 } 282 }, [requeueMissingStatus == null ? void 0 : requeueMissingStatus.isRunning]); 283 reactExports.useEffect(() => { 284 if (!(requeueMissingStatus == null ? void 0 : requeueMissingStatus.isRunning) && !isRequeuingMissing) return; 285 const interval = setInterval(() => { 286 fetchRequeueMissingStatus(); 287 }, 1500); 288 return () => clearInterval(interval); 289 }, [requeueMissingStatus == null ? void 0 : requeueMissingStatus.isRunning, isRequeuingMissing, fetchRequeueMissingStatus]); 290 const [bgQueueStatus, setBgQueueStatus] = reactExports.useState(null); 291 const fetchBgQueueStatus = reactExports.useCallback(async () => { 292 try { 293 const data = await api.getQueueAllUnhealthyStatus(); 294 setBgQueueStatus(data); 295 } catch (e) { 296 console.error("Failed to fetch bg queue status", e); 297 } 298 }, []); 299 reactExports.useEffect(() => { 300 if (!(bgQueueStatus == null ? void 0 : bgQueueStatus.isRunning)) return; 301 const interval = setInterval(() => { 302 fetchBgQueueStatus(); 303 }, 1500); 304 return () => clearInterval(interval); 305 }, [bgQueueStatus == null ? void 0 : bgQueueStatus.isRunning, fetchBgQueueStatus]); 306 const fetchBackfillStats = reactExports.useCallback(async (isManualRefresh = false) => { 307 if (isFetchingBackfillRef.current) return; 308 isFetchingBackfillRef.current = true; 309 try { 310 const url = isManualRefresh ? "/api/admin/worker/backfill-stats?refresh=true" : "/api/admin/worker/backfill-stats"; 311 const res = await fetch(url); 312 if (res.ok) { 313 const data = await res.json(); 314 setBackfillStats(data); 315 setBackfillError(null); 316 } else { 317 const errData = await res.json().catch(() => ({})); 318 setBackfillError(errData.error || `Failed to fetch telemetry (${res.status})`); 319 } 320 } catch (e) { 321 console.error("Failed to fetch backfill stats", e); 322 setBackfillError((e == null ? void 0 : e.message) || "Network error fetching backfill statistics"); 323 } finally { 324 isFetchingBackfillRef.current = false; 325 } 326 }, []); 327 const fetchPersistentErrors = reactExports.useCallback(async () => { 328 setIsLoadingErrors(true); 329 try { 330 const res = await fetch("/api/admin/workers/errors"); 331 if (res.ok) { 332 const data = await res.json(); 333 setPersistentErrors(data); 334 } 335 } catch (e) { 336 console.error("Failed to fetch persistent worker errors", e); 337 } finally { 338 setIsLoadingErrors(false); 339 } 340 }, []); 341 const handleReprocessError = async (id) => { 342 try { 343 const res = await fetch(`/api/admin/workers/errors/${id}/reprocess`, { 344 method: "POST" 345 }); 346 if (res.ok) { 347 alert(`MIDI ID #${id} successfully queued for reprocessing.`); 348 fetchPersistentErrors(); 349 refresh(); 350 } else { 351 const data = await res.json(); 352 alert(`Failed to reprocess: ${data.error || "Unknown error"}`); 353 } 354 } catch (e) { 355 alert(`Error: ${e.message}`); 356 } 357 }; 358 const handleDismissError = async (id) => { 359 if (!confirm(`Are you sure you want to dismiss the error record for MIDI ID #${id}?`)) return; 360 try { 361 const res = await fetch(`/api/admin/workers/errors/${id}`, { 362 method: "DELETE" 363 }); 364 if (res.ok) { 365 fetchPersistentErrors(); 366 } else { 367 const data = await res.json(); 368 alert(`Failed to dismiss error: ${data.error || "Unknown error"}`); 369 } 370 } catch (e) { 371 alert(`Error: ${e.message}`); 372 } 373 }; 374 const applyExpressPreset = async () => { 375 const expressSteps = ["clean", "meta_analysis", "audio_render", "waveform_gen", "final_analysis", "thumbnail"]; 376 const newConfig = { ...config, enabledSteps: expressSteps }; 377 setConfig(newConfig); 378 await handleSaveConfig(newConfig); 379 }; 380 const applyFullPreset = async () => { 381 const fullSteps = pipelineSteps.map((s) => s.slug); 382 const newConfig = { ...config, enabledSteps: fullSteps }; 383 setConfig(newConfig); 384 await handleSaveConfig(newConfig); 385 }; 386 const handleSaveConverterConfig = async () => { 387 setIsSavingConverterConfig(true); 388 try { 389 await api.saveSystemSetting("converter_config", { tempFilesLifetimeHours: converterLifetimeHours }); 390 alert("MIDI Converter retention policy updated successfully!"); 391 } catch (e) { 392 console.error("Failed to save converter config", e); 393 alert(`Failed to save policy: ${e.message}`); 394 } finally { 395 setIsSavingConverterConfig(false); 396 } 397 }; 398 const initData = reactExports.useCallback(async () => { 399 try { 400 const conf = await api.getAdminSystemSetting("worker_config");
401 try { 402 const convConfig = await api.getAdminSystemSetting("converter_config"); 403 if ((convConfig == null ? void 0 : convConfig.value) && typeof convConfig.value === "object") { 404 const val = convConfig.value.tempFilesLifetimeHours; 405 if (val !== void 0) setConverterLifetimeHours(Number(val)); 406 } 407 } catch (ce) { 408 console.error("Failed to load converter config", ce); 409 } 410 try { 411 const res = await fetch("/api/admin/worker/overwrite_status"); 412 if (res.ok) { 413 const data = await res.json(); 414 setOverwriteFiles(data.overwrite); 415 } 416 } catch (ce) { 417 console.error("Failed to load overwrite status", ce); 418 } 419 if (conf == null ? void 0 : conf.value) { 420 const cfg = conf.value; 421 if (!cfg.enabledSteps) cfg.enabledSteps = []; 422 if (cfg.poll_interval === void 0) cfg.poll_interval = 5; 423 if (cfg.max_threads === void 0) cfg.max_threads = 8; 424 if (cfg.cpu_threshold === void 0) cfg.cpu_threshold = 80; 425 setConfig(cfg); 426 } 427 try { 428 const steps = await api.getWorkerPipelineSteps(); 429 if (steps && Array.isArray(steps) && steps.length > 0) { 430 setPipelineSteps(steps); 431 setPipelineError(null); 432 } else if (steps && Array.isArray(steps)) { 433 setPipelineError("Manifest file found but empty."); 434 } else { 435 setPipelineError("Failed to load worker manifest."); 436 } 437 } catch (se) { 438 console.error("Step discovery failed", se); 439 setPipelineError("Worker offline or manifest missing."); 440 } 441 } catch (e) { 442 console.error("Worker init failed", e); 443 } 444 }, []); 445 const fetchWorkerNodes = reactExports.useCallback(async () => { 446 setIsLoadingNodes(true); 447 try { 448 const res = await fetch("/api/admin/worker/nodes"); 449 if (res.ok) { 450 const data = await res.json(); 451 if (Array.isArray(data)) { 452 setWorkerNodes(data); 453 } 454 } 455 } catch (e) { 456 console.error("Failed to fetch worker nodes", e); 457 } finally { 458 setIsLoadingNodes(false); 459 } 460 }, []); 461 const toggleWorkerEnabled = async (nodeId, currentlyEnabled) => { 462 const node = workerNodes.find((n) => n.id === nodeId); 463 if (!node) return; 464 const newEnabled = !currentlyEnabled; 465 if (newEnabled) { 466 setWorkerNodes((prev) => prev.map((n) => n.id === nodeId ? { ...n, config: { ...n.config, isStarting: true } } : n)); 467 } 468 try { 469 const res = await fetch(`/api/admin/worker/nodes/${nodeId}/config`, { 470 method: "POST", 471 headers: { "Content-Type": "application/json" }, 472 body: JSON.stringify({ 473 enabled: newEnabled, 474 poll_interval: node.config.poll_interval, 475 max_threads: node.config.max_threads, 476 cpu_threshold: node.config.cpu_threshold 477 }) 478 }); 479 if (res.ok) { 480 const data = await res.json(); 481 if (data && data.success) { 482 setWorkerNodes((prev) => prev.map((n) => n.id === nodeId ? { ...n, config: { ...n.config, enabled: newEnabled, isStarting: false } } : n)); 483 } else { 484 setWorkerNodes((prev) => prev.map((n) => n.id === nodeId ? { ...n, config: { ...n.config, isStarting: false } } : n)); 485 } 486 } else { 487 setWorkerNodes((prev) => prev.map((n) => n.id === nodeId ? { ...n, config: { ...n.config, isStarting: false } } : n)); 488 } 489 } catch (e) { 490 console.error("Error toggling worker status:", e); 491 setWorkerNodes((prev) => prev.map((n) => n.id === nodeId ? { ...n, config: { ...n.config, isStarting: false } } : n)); 492 } 493 }; 494 const saveWorkerConfig = async (nodeId, poll_interval, max_threads, cpu_threshold, scale, tasks_per_cpu, parallelExecution, silent = false) => { 495 const node = workerNodes.find((n) => n.id === nodeId); 496 if (!node) return; 497 try { 498 const res = await fetch(`/api/admin/worker/nodes/${nodeId}/config`, { 499 method: "POST", 500 headers: { "Content-Type": "application/json" }, 501 body: JSON.stringify({ 502 enabled: node.config.enabled, 503 poll_interval, 504 max_threads, 505 cpu_threshold, 506 scale, 507 tasks_per_cpu, 508 parallelExecution 509 }) 510 }); 511 if (res.ok) { 512 const data = await res.json(); 513 if (data && data.success) { 514 setWorkerNodes((prev) => prev.map((n) => n.id === nodeId ? { 515 ...n, 516 config: { ...n.config, poll_interval, max_threads, cpu_threshold, scale, tasks_per_cpu, parallelExecution } 517 } : n)); 518 setExpandedWorkerConfig((prev) => ({ ...prev, [nodeId]: false })); 519 if (!silent) alert(`Successfully updated config for ${node.name}!`); 520 } 521 } 522 } catch (e) { 523 console.error("Error saving worker config:", e); 524 if (!silent) alert("Error saving worker config."); 525 } 526 }; 527 const handleAutoTune = (node) => { 528 var _a2, _b2, _c2, _d2; 529 const cpus = ((_a2 = node.specs) == null ? void 0 : _a2.total_cpu) || ((_b2 = node.heartbeat) == null ? void 0 : _b2.total_cpu); 530 const totalRamBytes = ((_c2 = node.specs) == null ? void 0 : _c2.total_ram) || ((_d2 = node.heartbeat) == null ? void 0 : _d2.total_ram); 531 if (!cpus || !totalRamBytes) { 532 alert(`Cannot auto-tune because host resource specifications are unknown for ${node.name}. Please ensure the worker container is running, updated to the latest version, and reporting statistics.`); 533 return; 534 } 535 const ramGb = Math.round(totalRamBytes / (1024 * 1024 * 1024)); 536 let threadsPerWorker = 2; 537 let usableRam = ramGb - 2;
538 if (usableRam < 2) { 539 usableRam = 2; 540 } 541 const maxThreadsSupportedByRam = Math.floor(usableRam / 1.5); 542 let multiplier = 1; 543 const tasksPerCpuSelect = document.getElementById(`worker-tasks-per-cpu-${node.id}`); 544 if (tasksPerCpuSelect) { 545 tasksPerCpuSelect.value = String(multiplier); 546 } 547 let maxTotalThreads = cpus * multiplier; 548 if (maxTotalThreads > maxThreadsSupportedByRam) { 549 maxTotalThreads = maxThreadsSupportedByRam; 550 } 551 if (maxTotalThreads < 2) { 552 maxTotalThreads = 2; 553 } 554 let workers = Math.floor(maxTotalThreads / threadsPerWorker); 555 if (node.id === 3) { 556 workers = 1; 557 threadsPerWorker = maxTotalThreads; 558 } else if (workers < 1) { 559 workers = 1; 560 } 561 if (workers === 1) { 562 threadsPerWorker = maxTotalThreads; 563 } 564 const pollInput = document.getElementById(`worker-poll-${node.id}`); 565 const threadsInput = document.getElementById(`worker-threads-${node.id}`); 566 const cpuInput = document.getElementById(`worker-cpu-${node.id}`); 567 const scaleInput = document.getElementById(`worker-scale-${node.id}`); 568 if (pollInput) pollInput.value = "5"; 569 if (threadsInput) threadsInput.value = String(threadsPerWorker); 570 if (cpuInput) cpuInput.value = "80"; 571 if (scaleInput) scaleInput.value = String(workers); 572 }; 573 const fetchWorkerTasks = async (nodeId) => { 574 try { 575 const res = await fetch(`/api/admin/worker/nodes/${nodeId}/tasks`); 576 if (res.ok) { 577 const data = await res.json(); 578 if (Array.isArray(data)) {
579 setActiveWorkerTasks((prev) => ({ ...prev, [nodeId]: data })); 580 } 581 } 582 } catch (e) { 583 console.error("Failed to fetch tasks for node", nodeId, e); 584 } 585 }; 586 const handleRestartWorker = async (nodeId) => { 587 const node = workerNodes.find((n) => n.id === nodeId); 588 if (!node) return; 589 if (!window.confirm(`Are you sure you want to restart all worker services on ${node.name}?`)) { 590 return; 591 } 592 setRestartingNodes((prev) => ({ ...prev, [nodeId]: true })); 593 try { 594 const res = await fetch(`/api/admin/worker/nodes/${nodeId}/restart`, { 595 method: "POST" 596 }); 597 if (res.ok) { 598 const data = await res.json(); 599 if (data && data.success) { 600 alert(`Restart command successfully sent to ${node.name}!`); 601 setTimeout(fetchWorkerNodes, 3e3); 602 } else { 603 alert(`Failed to restart: ${data.error || "Unknown error"}`); 604 } 605 } else { 606 const text = await res.text(); 607 alert(`Failed to restart: ${text}`); 608 } 609 } catch (e) { 610 console.error("Error restarting worker:", e); 611 alert(`Error restarting worker: ${e.message}`); 612 } finally { 613 setRestartingNodes((prev) => ({ ...prev, [nodeId]: false })); 614 } 615 }; 616 const handleDiagnoseWorker = async (nodeId) => { 617 setDiagnosingNodes((prev) => ({ ...prev, [nodeId]: true })); 618 setDiagnosticReports((prev) => ({ ...prev, [nodeId]: "" })); 619 try { 620 const res = await fetch(`/api/admin/worker/nodes/${nodeId}/diagnose`); 621 if (res.ok) { 622 const data = await res.json(); 623 if (data && data.report) { 624 setDiagnosticReports((prev) => ({ ...prev, [nodeId]: data.report })); 625 } else if (data && data.error) { 626 setDiagnosticReports((prev) => ({ ...prev, [nodeId]: `Error: ${data.error}` })); 627 } else { 628 setDiagnosticReports((prev) => ({ ...prev, [nodeId]: "Unknown error occurred during diagnosis." })); 629 } 630 } else { 631 const text = await res.text(); 632 setDiagnosticReports((prev) => ({ ...prev, [nodeId]: `Diagnosis failed (HTTP ${res.status}): ${text}` })); 633 } 634 } catch (e) { 635 console.error("Diagnosis failed", e); 636 setDiagnosticReports((prev) => ({ ...prev, [nodeId]: `Diagnosis failed: ${e.message}` })); 637 } finally { 638 setDiagnosingNodes((prev) => ({ ...prev, [nodeId]: false })); 639 } 640 }; 641 const refresh = reactExports.useCallback(async () => { 642 try { 643 const stat = await api.getWorkerStatus(); 644 setStatus(stat); 645 setLastRefreshedAt(/* @__PURE__ */ new Date()); 646 setIsLoadingStatus(false); 647 const logUrl = selectedInstance === "unified" ? "/api/admin/worker/logs" : `/api/admin/worker/logs?instance=${selectedInstance}`; 648 const logRes = await fetch(logUrl); 649 if (logRes.ok) { 650 const data = await logRes.json(); 651 const fetchedLogs = data.logs || []; 652 latestLogsRef.current = fetchedLogs; 653 if (autoScroll) { 654 setLogs(fetchedLogs); 655 } 656 } 657 try { 658 const instRes = await api.getWorkerInstances(); 659 if (instRes) { 660 if (instRes.instances) { 661 setInstances(instRes.instances); 662 if (selectedInstance !== "unified") { 663 const stillExists = instRes.instances.some((inst) => String(inst.pid) === selectedInstance); 664 if (!stillExists) { 665 setSelectedInstance("unified"); 666 } 667 } 668 } 669 if (instRes.stats) { 670 setThroughputStats(instRes.stats); 671 } 672 if (instRes.system) { 673 setSystemStats(instRes.system); 674 } 675 } 676 } catch (instErr) { 677 console.error("Worker instances polling failed", instErr); 678 } 679 } catch (e) { 680 console.error("Worker refresh failed", e); 681 } finally { 682 setIsLoadingStatus(false); 683 } 684 }, [selectedInstance, autoScroll]); 685 reactExports.useEffect(() => { 686 if (autoScroll) { 687 setLogs(latestLogsRef.current); 688 } 689 }, [autoScroll]); 690 reactExports.useEffect(() => {
691 setLogs([]); 692 setAutoScroll(true); 693 }, [selectedInstance]); 694 reactExports.useEffect(() => { 695 if (instances.length > 0) { 696 if (isFirstScaleLoad.current || targetScale === 1) { 697 setTargetScale(instances.length); 698 isFirstScaleLoad.current = false; 699 } 700 } 701 }, [instances.length]); 702 const handleScaleCluster = async (target) => { 703 if (target === instances.length) return; 704 const isScaleDown = target < instances.length; 705 const diff = Math.abs(target - instances.length); 706 if (isScaleDown) { 707 if (!confirm(`Are you sure you want to scale down the worker cluster by ${diff} instance(s) gracefully? 708 709This triggers the Co-operative Graceful Shutdown Protocol: workers will finish any active MIDI processing jobs before exiting safely.`)) { 710 return; 711 } 712 } 713 setIsScalingCluster(true); 714 try { 715 await api.spawnWorkerInstance(void 0, target); 716 const instRes = await api.getWorkerInstances(); 717 if (instRes && instRes.instances) { 718 setInstances(instRes.instances); 719 } 720 } catch (e) { 721 console.error("Failed to scale worker cluster", e); 722 alert(`Failed to scale cluster: ${e.message}`); 723 } finally { 724 setIsScalingCluster(false); 725 } 726 }; 727 const handleCloseIdleInstances = async () => { 728 setIsClosingIdle(true); 729 try { 730 const res = await api.closeIdleWorkerInstances(); 731 alert(`Successfully closed ${res.closedCount} idle instances. New worker count: ${res.scale}`); 732 const instRes = await api.getWorkerInstances(); 733 if (instRes && instRes.instances) { 734 setInstances(instRes.instances); 735 } 736 } catch (e) { 737 console.error("Failed to close idle instances", e); 738 alert(`Failed to close idle instances: ${e.message}`); 739 } finally { 740 setIsClosingIdle(false); 741 } 742 }; 743 const handleTerminateInstance = async (pid) => { 744 const isRemote = typeof pid === "string" && (pid.startsWith("win108_") || pid.startsWith("gcp3_") || pid.startsWith("gcp4_")); 745 const modalMessage = isRemote ? `Are you sure you want to restart remote worker instance ${pid}? 746 747This will trigger a safe Docker container restart on the remote host.` : `Are you sure you want to stop worker instance PID ${pid} gracefully? 748 749If it is currently processing a MIDI track, it will complete the track before exiting safely.`; 750 if (!confirm(modalMessage)) return; 751 try { 752 await api.terminateWorkerInstance(pid); 753 const instRes = await api.getWorkerInstances(); 754 if (instRes && instRes.instances) { 755 setInstances(instRes.instances); 756 } 757 } catch (e) { 758 console.error(`Failed to ${isRemote ? "restart" : "terminate"} worker instance gracefully`, e); 759 alert(`Failed to ${isRemote ? "restart" : "terminate"} worker gracefully: ${e.message}`); 760 } 761 }; 762 reactExports.useEffect(() => { 763 initData(); 764 fetchWorkerNodes(); 765 refresh(); 766 fetchBackfillStats(); 767 fetchPersistentErrors(); 768 fetchBgQueueStatus(); 769 const interval = setInterval(() => { 770 if (!isPollingPaused) { 771 fetchWorkerNodes(); 772 refresh(); 773 fetchBgQueueStatus(); 774 if (autoRefreshErrors) { 775 fetchPersistentErrors(); 776 } 777 } 778 }, 5e3); 779 const backfillInterval = setInterval(() => { 780 if (!isPollingPaused) { 781 fetchBackfillStats(); 782 } 783 }, 3e4); 784 return () => { 785 clearInterval(interval); 786 clearInterval(backfillInterval); 787 }; 788 }, [initData, refresh, fetchWorkerNodes, fetchBackfillStats, fetchPersistentErrors, fetchBgQueueStatus, autoRefreshErrors, isPollingPaused]); 789 reactExports.useEffect(() => { 790 if (autoScroll && logContainerRef.current) { 791 const el = logContainerRef.current; 792 el.scrollTop = el.scrollHeight; 793 } 794 }, [logs, autoScroll]); 795 const handleSaveConfig = async (overrideConfig) => { 796 setIsSaving(true); 797 try { 798 await api.saveSystemSetting("worker_config", overrideConfig || config); 799 if (overrideConfig) setConfig(overrideConfig); 800 } catch (e) { 801 console.error("Failed to save worker configuration", e); 802 } finally { 803 setIsSaving(false); 804 } 805 }; 806 const toggleEnabled = async () => { 807 const newConfig = { ...config, enabled: !config.enabled }; 808 await handleSaveConfig(newConfig); 809 }; 810 const toggleOverwrite = async () => { 811 const newOverwrite = !overwriteFiles; 812 setOverwriteFiles(newOverwrite); 813 try { 814 await fetch("/api/admin/worker/toggle_overwrite", { 815 method: "POST", 816 headers: { "Content-Type": "application/json" }, 817 body: JSON.stringify({ overwrite: newOverwrite }) 818 }); 819 } catch (e) { 820 console.error("Failed to toggle overwrite", e); 821 setOverwriteFiles(!newOverwrite); 822 } 823 }; 824 const handleSelectAll = () => { 825 setConfig((prev) => { 826 const allSelected = pipelineSteps.length > 0 && pipelineSteps.every((s) => (prev.enabledSteps || []).includes(s.slug)); 827 if (allSelected) { 828 return { ...prev, enabledSteps: [] }; 829 } else { 830 return { ...prev, enabledSteps: pipelineSteps.map((s) => s.slug) }; 831 } 832 }); 833 }; 834 const toggleStep = (slug) => { 835 setConfig((prev) => { 836 const current = prev.enabledSteps || []; 837 if (current.includes(slug)) { 838 return { ...prev, enabledSteps: current.filter((s) => s !== slug) }; 839 } else { 840 return { ...prev, enabledSteps: [...current, slug] }; 841 } 842 }); 843 }; 844 const handleResetStuck = async () => { 845 if (!confirm("This will reset all 'Processing' and 'Failed' tasks back to 'Pending'. Continue?")) return; 846 try { 847 await api.resetStuckTasks(); 848 alert("Tasks have been reset to 'Pending'."); 849 refresh(); 850 } catch (error) { 851 console.error("Failed to reset stuck tasks", error); 852 alert("Error: Could not reset tasks. Check console for details."); 853 } 854 }; 855 const handleClearQueue = async () => { 856 if (!confirm("This will revert/pause ALL pending tasks currently in the queue. Continue?")) return; 857 try { 858 const res = await api.clearQueueTasks(); 859 alert(`${res.count} pending tasks have been removed from the active queue.`); 860 refresh(); 861 } catch (error) { 862 console.error("Failed to clear queue", error); 863 alert("Error: Could not clear queue. Check console for details."); 864 } 865 }; 866 const handleStopAll = async () => { 867 if (!confirm("â ï¸ EMERGENCY STOP:\n\nThis will instantly REVERT all pending AND actively processing tasks, and restart all workers to abort current conversions immediately.\n\nAre you sure you want to stop all processing?")) return; 868 try { 869 const res = await api.stopAllTasks(); 870 alert(`Emergency Stop Triggered! ${res.count} tasks have been reverted/paused, and background workers are restarting to abort running jobs.`); 871 refresh(); 872 } catch (error) { 873 console.error("Failed to stop processing", error); 874 alert("Error: Could not trigger emergency stop. Check console for details."); 875 } 876 }; 877 const handleClearFailures = async () => { 878 if (!confirm("This will move ALL failed/rejected tasks out of DB Failures to 'Paused' state. Continue?")) return; 879 try { 880 const res = await api.clearFailureTasks(); 881 alert(`${res.count} failed tasks have been moved to 'Paused' state.`); 882 refresh(); 883 } catch (error) { 884 console.error("Failed to clear failures", error); 885 alert("Error: Could not clear failures. Check console for details."); 886 } 887 }; 888 const handleClearLogs = async () => { 889 if (!confirm("Are you sure you want to clear the worker log file?")) return; 890 try { 891 await api.clearWorkerLogs(); 892 setLogs([]); 893 } catch (e) { 894 console.error("Failed to clear logs", e); 895 } 896 }; 897 const handleRunIntegrityCheck = async () => { 898 setIsCheckingIntegrity(true); 899 try { 900 const start = integrityStartId ? parseInt(integrityStartId, 10) : void 0; 901 const end = integrityEndId ? parseInt(integrityEndId, 10) : void 0; 902 const checkPromise = api.runMIDIIntegrityCheck( 903 start && !isNaN(start) ? start : void 0,
904 end && !isNaN(end) ? end : void 0 905 ); 906 const mapPromise = start !== void 0 && end !== void 0 && !isNaN(start) && !isNaN(end) ? api.getMIDIMap(start, end) : Promise.resolve(null); 907 const [result, mapResult] = await Promise.all([checkPromise, mapPromise]); 908 if (result && result.success) { 909 setIntegrityResult(result); 910 setSelectedUnhealthyIds((result.unhealthyTracks || []).map((t) => t.id)); 911 } 912 if (mapResult && mapResult.success) { 913 setMapTracks(mapResult.tracks || []); 914 setSelectedMapTrack(null); 915 } 916 } catch (e) { 917 console.error("Failed to run MIDI integrity check", e); 918 alert(`Integrity Check failed: ${e.message}`); 919 } finally { 920 setIsCheckingIntegrity(false); 921 } 922 }; 923 const handleRequeueMissing = async () => { 924 if (!confirm("Are you sure you want to scan all missing files on storage and re-queue the ones that are found?")) { 925 return; 926 } 927 setIsRequeuingMissing(true); 928 try { 929 const res = await api.requeueMissingFound(); 930 if (res && res.success) { 931 alert(res.message); 932 refresh(); 933 } else { 934 alert(`Error: ${res.message || "Unknown response"}`); 935 } 936 } catch (e) { 937 console.error("Failed to requeue missing tracks", e); 938 alert(`Re-queue failed: ${e.message}`); 939 } finally { 940 setIsRequeuingMissing(false); 941 } 942 }; 943 const handleReprocessSelected = async (missingOnly) => {
944 if (selectedUnhealthyIds.length === 0) return; 945 const confirmMsg = missingOnly ? `Are you sure you want to regenerate ONLY the missing files for the ${selectedUnhealthyIds.length} selected track(s)?` : `Are you sure you want to trigger full reprocessing for the ${selectedUnhealthyIds.length} selected track(s)? This will rebuild all media and analysis from scratch.`; 946 if (!confirm(confirmMsg)) return; 947 setIsReprocessing(true); 948 try { 949 const res = await api.reprocessUnhealthyMIDIs({ ids: selectedUnhealthyIds }, { requeueMissing: missingOnly }); 950 if (res && res.success) { 951 alert(res.message); 952 await handleRunIntegrityCheck(); 953 refresh(); 954 } 955 } catch (e) { 956 console.error("Failed to reprocess tracks", e); 957 alert(`Reprocessing failed: ${e.message}`); 958 } finally { 959 setIsReprocessing(false); 960 } 961 }; 962 const handleQueueAllUnhealthy = async () => { 963 let confirmMsg = `Are you sure you want to run the Storage Asset Integrity Check & Sync? 964 965`; 966 confirmMsg += `Mode: ${integrityScanMode} 967`; 968 if (integrityScanMode === "idRange") confirmMsg += `Range: ${integrityStartId || 1} to ${integrityEndId || "Max"} 969`; 970 if (integrityScanMode === "singleId") confirmMsg += `ID: ${integritySingleId} 971`; 972 if (integrityScanMode === "dateRange") confirmMsg += `Date Field: ${integrityDateField} 973Start: ${integrityStartDate || "Any"} 974End: ${integrityEndDate || "Any"} 975`; 976 if (integrityScanMode === "status") confirmMsg += `Status: ${integrityStatusFilter} 977`; 978 if (integrityScanMode === "specificFileMissing") confirmMsg += `Missing File Key: ${integrityMissingFile} 979`; 980 confirmMsg += ` 981Requeue Missing Files: ${integrityRequeueMissing ? "YES" : "NO"} 982`; 983 confirmMsg += ` 984This background process will scan physical files, synchronize the database generatedFiles state, and automatically flag missing files.`; 985 if (!confirm(confirmMsg)) return; 986 setIsReprocessing(true); 987 try { 988 const filters = {}; 989 if (integrityScanMode === "singleId") { 990 filters.singleId = integritySingleId; 991 } else if (integrityScanMode === "idRange") { 992 filters.idRange = { startId: integrityStartId, endId: integrityEndId }; 993 } else if (integrityScanMode === "dateRange") { 994 filters.dateRange = { startDate: integrityStartDate, endDate: integrityEndDate, dateField: integrityDateField }; 995 } else if (integrityScanMode === "status") { 996 filters.status = integrityStatusFilter; 997 } else if (integrityScanMode === "specificFileMissing") { 998 filters.specificFileMissing = integrityMissingFile; 999 } else if (integrityScanMode === "all") { 1000 } 1001 const options = { requeueMissing: integrityRequeueMissing }; 1002 const res = await api.reprocessUnhealthyMIDIs(filters, options); 1003 if (res && res.success) { 1004 alert(res.message); 1005 fetchBgQueueStatus(); 1006 refresh(); 1007 } 1008 } catch (e) { 1009 console.error("Failed to run integrity check", e); 1010 alert(`Integrity Scan failed: ${e.message}`); 1011 } finally { 1012 setIsReprocessing(false); 1013 } 1014 }; 1015 const handleBulkReprocessRange = async () => { 1016 const start = parseInt(bulkStartId, 10); 1017 const end = parseInt(bulkEndId, 10); 1018 if (isNaN(start) || isNaN(end)) { 1019 alert("Please enter a valid Start ID and End ID range."); 1020 return; 1021 } 1022 if (start > end) { 1023 alert("Start ID cannot be greater than End ID."); 1024 return; 1025 } 1026 const count = end - start + 1; 1027 const steps = bulkFullProcess ? void 0 : bulkSteps; 1028 if (!bulkFullProcess && bulkSteps.length === 0) { 1029 alert("Please select at least one step type to reprocess, or choose 'Full Process'."); 1030 return; 1031 } 1032 const confirmMsg = bulkFullProcess ? `Are you sure you want to trigger FULL re-processing for the track ID range ${start} to ${end} (~${count} tracks)? 1033This will re-run all pipeline steps and rebuild files from scratch.` : `Are you sure you want to selectively trigger re-processing of types [${bulkSteps.join(", ")}] for the track ID range ${start} to ${end} (~${count} tracks)?`; 1034 if (!confirm(confirmMsg)) return; 1035 setIsBulkProcessing(true); 1036 try { 1037 const res = await api.reprocessMIDIRange(start, end, steps, bulkSkipCompleted); 1038 if (res && res.success) { 1039 alert(res.message || `Successfully queued ${res.count} tracks in range ${start}â${end} for processing.`); 1040 refresh(); 1041 } else { 1042 alert("An error occurred queuing range reprocessing."); 1043 } 1044 } catch (e) { 1045 console.error("Bulk range reprocessing failed", e); 1046 alert(`Queuing failed: ${e.message}`); 1047 } finally { 1048 setIsBulkProcessing(false); 1049 } 1050 }; 1051 const handleToggleSelectUnhealthy = (id) => {
1052 setSelectedUnhealthyIds( 1053 (prev) => prev.includes(id) ? prev.filter((i) => i !== id) : [...prev, id] 1054 ); 1055 }; 1056 const handleToggleSelectAllUnhealthy = () => { 1057 if (!integrityResult) return; 1058 const tracks = integrityResult.unhealthyTracks || []; 1059 if (selectedUnhealthyIds.length === tracks.length) { 1060 setSelectedUnhealthyIds([]); 1061 } else { 1062 setSelectedUnhealthyIds(tracks.map((t) => t.id)); 1063 } 1064 }; 1065 const handleSingleReprocess = async (id, missingOnly = false) => { 1066 const confirmMsg = missingOnly ? `Are you sure you want to regenerate ONLY the missing files for MIDI ID #${id}?` : `Are you sure you want to trigger full reprocessing for MIDI ID #${id}? This will rebuild all media and analysis from scratch.`; 1067 if (!confirm(confirmMsg)) return; 1068 try { 1069 const res = await api.reprocessUnhealthyMIDIs({ ids: [id] }, { requeueMissing: missingOnly }); 1070 if (res && res.success) { 1071 alert(missingOnly ? `Queued ID #${id} for missing assets regeneration.` : `Queued ID #${id} for reprocessing.`); 1072 const start = integrityStartId ? parseInt(integrityStartId, 10) : void 0; 1073 const end = integrityEndId ? parseInt(integrityEndId, 10) : void 0; 1074 const checkPromise = api.runMIDIIntegrityCheck(start, end); 1075 const mapPromise = start !== void 0 && end !== void 0 && !isNaN(start) && !isNaN(end) ? api.getMIDIMap(start, end) : Promise.resolve(null); 1076 const [checkRes, mapRes] = await Promise.all([checkPromise, mapPromise]); 1077 if (checkRes && checkRes.success) { 1078 setIntegrityResult(checkRes); 1079 setSelectedUnhealthyIds(checkRes.unhealthyTracks.map((t) => t.id)); 1080 } 1081 if (mapRes && mapRes.success) { 1082 setMapTracks(mapRes.tracks || []); 1083 const updatedTrack = mapRes.tracks.find((t) => t.id === id); 1084 if (updatedTrack) { 1085 setSelectedMapTrack(updatedTrack); 1086 } 1087 } 1088 refresh(); 1089 } 1090 } catch (e) { 1091 alert(`Reprocessing failed: ${e.message}`); 1092 } 1093 }; 1094 const handleTriggerReplaceForId = (id) => { 1095 setReplaceMidiId(String(id)); 1096 const el = document.getElementById("replace-midi-card"); 1097 if (el) { 1098 el.scrollIntoView({ behavior: "smooth" }); 1099 } 1100 }; 1101 const handlePrioritizeMidi = async () => { 1102 const trackId = parseInt(priorityMidiId, 10); 1103 if (isNaN(trackId)) { 1104 alert("Please enter a valid numeric MIDI ID."); 1105 return; 1106 } 1107 if (!confirm(`Are you sure you want to prioritize MIDI ID #${trackId} for immediate processing?`)) { 1108 return; 1109 } 1110 setIsPrioritizing(true); 1111 try { 1112 const res = await api.prioritizeMidi(trackId); 1113 alert(res.message || "MIDI prioritized successfully!"); 1114 setPriorityMidiId(""); 1115 refresh(); 1116 } catch (err) { 1117 alert(`Prioritization failed: ${err.message}`); 1118 } finally { 1119 setIsPrioritizing(false); 1120 } 1121 }; 1122 const getSortedTracks = (tracks) => { 1123 if (mapSortMode === "sequential") { 1124 return [...tracks].sort((a, b) => a.id - b.id); 1125 } 1126 return [...tracks].sort((a, b) => { 1127 const getPriority = (t) => { 1128 if (t.totalCreated === 0) return 1; 1129 if (t.totalCreated === t.totalExpected) return 2; 1130 return 3; 1131 }; 1132 const prioA = getPriority(a); 1133 const prioB = getPriority(b); 1134 if (prioA !== prioB) { 1135 return prioA - prioB; 1136 } 1137 if (prioA === 3) { 1138 if (b.totalCreated !== a.totalCreated) { 1139 return b.totalCreated - a.totalCreated; 1140 } 1141 } 1142 return a.id - b.id; 1143 }); 1144 }; 1145 const [isCleaning, setIsCleaning] = reactExports.useState(false); 1146 const [cleanupPatterns, setCleanupPatterns] = reactExports.useState("*_harmony_roman.xml, *_harmony_chords.xml"); 1147 const handleGarbageCollection = async () => { 1148 const patternsArray = cleanupPatterns.split(",").map((p) => p.trim()).filter(Boolean); 1149 if (patternsArray.length === 0) { 1150 alert("Please provide at least one pattern."); 1151 return; 1152 } 1153 if (!confirm(`This will permanently delete files matching [${patternsArray.join(", ")}] from the scores directory. Continue?`)) return; 1154 setIsCleaning(true); 1155 try { 1156 const res = await fetch("/api/admin/system/garbage-collection", { 1157 method: "POST", 1158 headers: { "Content-Type": "application/json" }, 1159 body: JSON.stringify({ patterns: patternsArray }) 1160 }); 1161 if (res.ok) { 1162 const data = await res.json(); 1163 alert(data.message || "Cleanup successful."); 1164 } else { 1165 const err = await res.json(); 1166 alert(`Cleanup failed: ${err.error}`); 1167 } 1168 } catch (e) { 1169 console.error("Garbage collection failed", e); 1170 alert("Error: Could not perform cleanup."); 1171 } finally { 1172 setIsCleaning(false); 1173 } 1174 }; 1175 const formatBytes = (bytes) => { 1176 if (!bytes) return "0 Bytes";
1177 const k = 1024; 1178 const sizes = ["Bytes", "KB", "MB", "GB"]; 1179 const i = Math.floor(Math.log(bytes) / Math.log(k)); 1180 return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; 1181 }; 1182 const hb = status.lastHeartbeat; 1183 const isValidString = typeof hb === "string"; 1184 const hbTime = hb && isValidString ? new Date(hb.endsWith("Z") ? hb : hb + "Z").getTime() : 0; 1185 const isOnline = hbTime > 0 && Date.now() - hbTime < 9e4 || instances && instances.length > 0; 1186 const lastSeen = hb && isValidString ? new Date(hb.endsWith("Z") ? hb : hb + "Z").toLocaleString() : instances && instances.length > 0 ? "Active" : "Never"; 1187 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full overflow-y-auto custom-scrollbar space-y-6 animate-in fade-in pb-20", children: [ 1188 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `p-3 px-5 rounded-xl border flex flex-col md:flex-row items-center justify-between gap-4 shadow-sm transition-all duration-300 ${isLoadingStatus ? "bg-zinc-50/80 dark:bg-zinc-900/40 border-zinc-200 dark:border-zinc-800" : isOnline ? "bg-emerald-50/65 dark:bg-emerald-900/10 border-emerald-200 dark:border-emerald-800/40" : "bg-red-50/65 dark:bg-red-900/10 border-red-200 dark:border-red-800/40"}`, children: [
1189 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 w-full md:w-auto", children: [ 1190 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `p-2 rounded-full ${isLoadingStatus ? "bg-zinc-100 dark:bg-zinc-800 text-zinc-500" : isOnline ? "bg-emerald-100 text-emerald-600" : "bg-red-100 text-red-600"}`, children: isLoadingStatus ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 20, className: "animate-spin text-zinc-500 dark:text-zinc-400" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 20, className: isOnline ? "animate-pulse" : "" }) }), 1191 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1192 /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: `text-base font-black ${isLoadingStatus ? "text-zinc-800 dark:text-zinc-200" : isOnline ? "text-emerald-900 dark:text-emerald-100" : "text-red-900 dark:text-red-100"}`, children: isLoadingStatus ? "Loading Worker Status..." : isOnline ? "Worker Online" : "Worker Offline" }),
1193 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-2 mt-0.5", children: [ 1194 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: `text-[10px] font-bold uppercase tracking-tight ${isLoadingStatus ? "text-zinc-400 dark:text-zinc-500" : isOnline ? "text-emerald-700 dark:text-emerald-300" : "text-red-700 dark:text-red-300"}`, children: isLoadingStatus ? "Connecting to worker services..." : `Seen: ${lastSeen}` }), 1195 lastRefreshedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-bold text-zinc-600 dark:text-zinc-300 flex items-center gap-1 bg-white/60 dark:bg-black/20 px-2 py-0.5 rounded-full border border-zinc-200/50 dark:border-zinc-700/50", children: [ 1196 /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { size: 10, className: "text-zinc-400" }), 1197 "Status Updated: ", 1198 lastRefreshedAt.toLocaleString() 1199 ] }) 1200 ] }) 1201 ] }) 1202 ] }), 1203 systemStats && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row items-center gap-6 w-full md:w-auto justify-center md:border-l border-zinc-200/50 dark:border-zinc-800/60 md:pl-6", children: [
1204 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full sm:w-40 flex flex-col", children: [ 1205 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[10px] font-black text-zinc-500 dark:text-zinc-400 uppercase tracking-wider mb-1.5", children: [ 1206 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 1207 /* @__PURE__ */ jsxRuntimeExports.jsx(Cpu, { size: 12, className: "text-zinc-400" }), 1208 " Host CPU Load" 1209 ] }), 1210 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono font-bold text-zinc-700 dark:text-zinc-300", children: [ 1211 systemStats.cpu, 1212 "%" 1213 ] }) 1214 ] }), 1215 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-zinc-200/60 dark:bg-zinc-800 h-2 rounded-full overflow-hidden shadow-inner", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 1216 "div", 1217 { 1218 className: "bg-indigo-600 h-full rounded-full transition-all duration-700 ease-out", 1219 style: { width: `${systemStats.cpu}%` } 1220 } 1221 ) }) 1222 ] }),
1223 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full sm:w-44 flex flex-col", children: [ 1224 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[10px] font-black text-zinc-500 dark:text-zinc-400 uppercase tracking-wider mb-1.5", children: [ 1225 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 1226 /* @__PURE__ */ jsxRuntimeExports.jsx(Gauge, { size: 12, className: "text-zinc-400" }), 1227 " Host Memory" 1228 ] }), 1229 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono font-bold text-zinc-700 dark:text-zinc-300", children: [ 1230 systemStats.memory.percentage, 1231 "%" 1232 ] }) 1233 ] }), 1234 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-zinc-200/60 dark:bg-zinc-800 h-2 rounded-full overflow-hidden shadow-inner", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 1235 "div", 1236 { 1237 className: "bg-pink-500 h-full rounded-full transition-all duration-700 ease-out", 1238 style: { width: `${systemStats.memory.percentage}%` } 1239 } 1240 ) }),
1241 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] font-mono text-zinc-400 font-bold text-right mt-1", children: [ 1242 systemStats.memory.used, 1243 " GB / ", 1244 systemStats.memory.total, 1245 " GB" 1246 ] }) 1247 ] }) 1248 ] }), 1249 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 w-full md:w-auto justify-end", children: [ 1250 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1251 "button", 1252 { 1253 onClick: () => setIsPollingPaused(!isPollingPaused), 1254 className: `px-3 py-1.5 rounded-lg text-xs font-bold flex items-center gap-2 transition-colors ${isPollingPaused ? "bg-amber-100 text-amber-700 hover:bg-amber-200 dark:bg-amber-900/20 dark:text-amber-300 dark:hover:bg-amber-900/30 border border-amber-200 dark:border-amber-800/40" : "bg-indigo-100 text-indigo-700 hover:bg-indigo-200 dark:bg-indigo-900/20 dark:text-indigo-300 dark:hover:bg-indigo-900/30 border border-indigo-200 dark:border-indigo-800/40"} w-full sm:w-auto justify-center`, 1255 children: [ 1256 isPollingPaused ? /* @__PURE__ */ jsxRuntimeExports.jsx(CirclePlay, { size: 14, className: "animate-pulse" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleStop, { size: 14 }), 1257 isIdlePaused ? "Paused (Idle â Move mouse to resume)" : isPollingPaused ? "Resume Auto-Update" : "Pause Auto-Update" 1258 ] 1259 } 1260 ),
1261 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1262 "button", 1263 { 1264 onClick: toggleEnabled, 1265 disabled: isSaving, 1266 className: `px-3 py-1.5 rounded-lg text-xs font-bold flex items-center gap-2 transition-colors ${config.enabled ? "bg-red-100 text-red-700 hover:bg-red-200" : "bg-emerald-100 text-emerald-700 hover:bg-emerald-200"} disabled:opacity-50 w-full sm:w-auto justify-center`, 1267 children: [ 1268 isSaving ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : config.enabled ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleStop, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CirclePlay, { size: 14 }), 1269 config.enabled ? "Pause" : "Resume" 1270 ] 1271 } 1272 ), 1273 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1274 "button", 1275 { 1276 onClick: toggleOverwrite, 1277 className: `px-3 py-1.5 rounded-lg text-xs font-bold flex items-center gap-2 transition-colors ${overwriteFiles ? "bg-rose-100 text-rose-700 hover:bg-rose-200 dark:bg-rose-900/20 dark:text-rose-300" : "bg-teal-100 text-teal-700 hover:bg-teal-200 dark:bg-teal-900/20 dark:text-teal-300"} w-full sm:w-auto justify-center`, 1278 title: overwriteFiles ? "Currently overwriting existing files. Click to skip." : "Currently skipping existing files. Click to overwrite.", 1279 children: [ 1280 overwriteFiles ? /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { size: 14 }), 1281 overwriteFiles ? "Overwrite: ON" : "Overwrite: OFF" 1282 ] 1283 } 1284 ) 1285 ] }) 1286 ] }), 1287 !isLoadingStatus && !isOnline && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800 p-4 rounded-xl flex gap-3", children: [
1288 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "text-amber-600 shrink-0", size: 24 }), 1289 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1290 /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "font-bold text-amber-900 dark:text-amber-100 text-sm", children: 'Troubleshooting "Worker Offline"' }), 1291 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-amber-800 dark:text-amber-200 mt-1 mb-2", children: [ 1292 "The worker container is not updating its heartbeat. Please check the logs below for errors or run:", 1293 /* @__PURE__ */ jsxRuntimeExports.jsx("br", {}), 1294 /* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "bg-amber-100 dark:bg-amber-900/40 px-1 py-0.5 rounded mt-1 inline-block", children: "docker compose logs -f worker" }) 1295 ] }) 1296 ] }) 1297 ] }), 1298 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center px-1 -mb-3", children: [ 1299 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-black uppercase text-zinc-500 flex items-center gap-1.5 tracking-wider", children: [
1300 /* @__PURE__ */ jsxRuntimeExports.jsx(Gauge, { size: 14, className: "text-indigo-500" }), 1301 " Pipeline Status Overview" 1302 ] }), 1303 lastRefreshedAt && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-mono text-zinc-400 dark:text-zinc-500 flex items-center gap-1", children: [ 1304 /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { size: 11, className: "text-indigo-400" }), 1305 "Status Date/Time: ", 1306 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-zinc-700 dark:text-zinc-300", children: lastRefreshedAt.toLocaleString() }) 1307 ] }) 1308 ] }), 1309 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 md:grid-cols-6 gap-3", children: [ 1310 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 p-3 rounded-xl border border-zinc-200 dark:border-zinc-800 shadow-sm", children: [ 1311 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500 text-[10px] font-black uppercase mb-0.5 tracking-wider", children: "Queue (DB + Temp)" }),
1312 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end justify-between", children: [ 1313 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-zinc-900 dark:text-white leading-tight", children: status.pending }), 1314 status.pending > 0 && throughputStats && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] text-zinc-400 font-bold mb-0.5", children: [ 1315 "ETC: ", 1316 calculateETC(status.pending, status.processing, ((_a = throughputStats.m10) == null ? void 0 : _a.perHour) || 0, ((_b = throughputStats.m30) == null ? void 0 : _b.perHour) || 0) 1317 ] }) 1318 ] }), 1319 /* @__PURE__ */ jsxRuntimeExports.jsx(SourcePills, { breakdown: (_c = status.sourceBreakdown) == null ? void 0 : _c.pending }) 1320 ] }), 1321 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 p-3 rounded-xl border border-zinc-200 dark:border-zinc-800 shadow-sm", children: [ 1322 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-indigo-500 text-[10px] font-black uppercase mb-0.5 tracking-wider", children: "Processing" }),
1323 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-indigo-600 dark:text-indigo-400 leading-tight", children: status.processing }), 1324 (status.processingByNode || status.throughputByNode) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-2 pt-2 border-t border-zinc-100 dark:border-zinc-800", children: [ 1325 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-1", children: [ 1326 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] font-bold text-zinc-400 uppercase", children: "Nodes & Throughput" }), 1327 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[7px] text-zinc-400 font-mono", children: "in-flight (hr rate)" }) 1328 ] }), 1329 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-1", children: [ 1330 [ 1331 { key: "hk", label: "HK", colorClass: "bg-sky-100 dark:bg-sky-900/40 text-sky-700 dark:text-sky-300" }, 1332 { key: "jp", label: "JP", colorClass: "bg-violet-100 dark:bg-violet-900/40 text-violet-700 dark:text-violet-300" }, 1333 { key: "gcp", label: "GCP", colorClass: "bg-emerald-100 dark:bg-emerald-900/40 text-emerald-700 dark:text-emerald-300" }, 1334 { key: "gcp_fast", label: "Fast", colorClass: "bg-teal-100 dark:bg-teal-900/40 text-teal-700 dark:text-teal-300" }, 1335 { key: "gcp_cleaver", label: "Cleaver", colorClass: "bg-cyan-100 dark:bg-cyan-900/40 text-cyan-700 dark:text-cyan-300" }, 1336 { key: "gpu", label: "GPU", colorClass: "bg-pink-100 dark:bg-pink-900/40 text-pink-700 dark:text-pink-300" }, 1337 { key: "midi", label: "MIDI", colorClass: "bg-amber-100 dark:bg-amber-900/40 text-amber-700 dark:text-amber-300" } 1338 ].map((n) => { 1339 var _a2, _b2; 1340 const inFlight = ((_a2 = status.processingByNode) == null ? void 0 : _a2[n.key]) || 0; 1341 const tp = ((_b2 = status.throughputByNode) == null ? void 0 : _b2[n.key]) || { m15: 0, h1: 0 }; 1342 const isRecentActive = inFlight > 0 || tp.m15 > 0; 1343 const hasAnyActivity = isRecentActive || tp.h1 > 0; 1344 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 1345 "span", 1346 { 1347 title: `${n.label} Node: ${inFlight} currently in-flight, ${tp.m15} completed in last 15m, ${tp.h1}/hr in last 60m`, 1348 className: `text-[9px] font-black uppercase px-1.5 py-0.5 rounded inline-flex items-center gap-1 transition-colors ${hasAnyActivity ? n.colorClass : "bg-zinc-100 dark:bg-zinc-800/60 text-zinc-400 dark:text-zinc-500"}`, 1349 children: [ 1350 isRecentActive && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" }), 1351 n.label, 1352 " ", 1353 inFlight > 0 ? inFlight : tp.m15 > 0 ? "Active" : tp.h1 > 0 ? "Idle" : "0", 1354 tp.h1 > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "opacity-75 font-normal", children: [ 1355 "(", 1356 tp.h1, 1357 "/h)" 1358 ] }) 1359 ] 1360 }, 1361 n.key 1362 ); 1363 }), 1364 ((((_d = status.processingByNode) == null ? void 0 : _d.unknown) || 0) > 0 || (((_f = (_e = status.throughputByNode) == null ? void 0 : _e.unknown) == null ? void 0 : _f.h1) || 0) > 0) && /* @__PURE__ */ jsxRuntimeExports.jsxs( 1365 "span", 1366 { 1367 title: `Batch Ingestion & Untagged Tasks: ${((_g = status.processingByNode) == null ? void 0 : _g.unknown) || 0} in-flight, ${((_i = (_h = status.throughputByNode) == null ? void 0 : _h.unknown) == null ? void 0 : _i.h1) || 0}/hr throughput`, 1368 className: "text-[9px] font-black uppercase bg-zinc-150 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 px-1.5 py-0.5 rounded inline-flex items-center gap-1", 1369 children: [ 1370 "Batch ", 1371 ((_j = status.processingByNode) == null ? void 0 : _j.unknown) || 0, 1372 (((_l = (_k = status.throughputByNode) == null ? void 0 : _k.unknown) == null ? void 0 : _l.h1) || 0) >
1372 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "opacity-75 font-normal", children: [ 1373 "(", 1374 (_n = (_m = status.throughputByNode) == null ? void 0 : _m.unknown) == null ? void 0 : _n.h1, 1375 "/h)" 1376 ] }) 1377 ] 1378 } 1379 ) 1380 ] }) 1381 ] }), 1382 /* @__PURE__ */ jsxRuntimeExports.jsx(SourcePills, { breakdown: (_o = status.sourceBreakdown) == null ? void 0 : _o.processing, withDivider: true }) 1383 ] }), 1384 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 p-3 rounded-xl border border-zinc-200 dark:border-zinc-800 shadow-sm", children: [ 1385 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-emerald-500 text-[10px] font-black uppercase mb-0.5 tracking-wider", children: "DB Completed" }), 1386 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-emerald-600 dark:text-emerald-400 leading-tight", children: status.completed }),
1387 /* @__PURE__ */ jsxRuntimeExports.jsx(SourcePills, { breakdown: (_p = status.sourceBreakdown) == null ? void 0 : _p.completed }) 1388 ] }), 1389 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 p-3 rounded-xl border border-zinc-200 dark:border-zinc-800 shadow-sm", children: [ 1390 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-teal-500 text-[10px] font-black uppercase mb-0.5 tracking-wider", children: "DB Metadata Only" }), 1391 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-teal-600 dark:text-teal-400 leading-tight", children: status.metadataOnly || 0 }), 1392 /* @__PURE__ */ jsxRuntimeExports.jsx(SourcePills, { breakdown: (_q = status.sourceBreakdown) == null ? void 0 : _q.metadataOnly }) 1393 ] }), 1394 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 p-3 rounded-xl border border-zinc-200 dark:border-zinc-800 shadow-sm", children: [ 1395 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-red-500 text-[10px] font-black uppercase mb-0.5 tracking-wider", children: "DB Failures" }),
1396 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-red-600 dark:text-red-400 leading-tight", children: status.rejected }), 1397 /* @__PURE__ */ jsxRuntimeExports.jsx(SourcePills, { breakdown: (_r = status.sourceBreakdown) == null ? void 0 : _r.failures }) 1398 ] }), 1399 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 p-3 rounded-xl border border-zinc-200 dark:border-zinc-800 shadow-sm flex flex-col justify-between", children: [ 1400 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1401 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-amber-500 text-[10px] font-black uppercase mb-0.5 tracking-wider", children: "DB Missing" }), 1402 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-amber-600 dark:text-amber-400 leading-tight", children: status.missing || 0 }), 1403 /* @__PURE__ */ jsxRuntimeExports.jsx(SourcePills, { breakdown: (_s = status.sourceBreakdown) == null ? void 0 : _s.missing }) 1404 ] }), 1405 status.missing !== void 0 && status.missing > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx( 1406 "button", 1407 { 1408 onClick: handleRequeueMissing, 1409 disabled: isRequeuingMissing, 1410 className: "mt-2 w-full text-center px-2 py-1 bg-amber-500 hover:bg-amber-600 disabled:bg-amber-800 text-white text-[9px] font-black uppercase rounded shadow-sm transition-all", 1411 children: isRequeuingMissing ? "Re-queuing..." : "Re-queue If Found" 1412 } 1413 ) 1414 ] }) 1415 ] }), 1416 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [
1417 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col md:flex-row items-start md:items-center justify-between gap-4 border-b border-zinc-100 dark:border-zinc-800 pb-4 mb-4", children: [ 1418 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1419 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-black uppercase text-zinc-900 dark:text-white flex items-center gap-2", children: [ 1420 /* @__PURE__ */ jsxRuntimeExports.jsx(TrendingUp, { size: 20, className: "text-indigo-500" }), 1421 " Backlog Clearance & Backfill Monitor" 1422 ] }), 1423 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 mt-1", children: "Monitor Express Ingestion clearance and chronological sheet music/stems backfill progress by MIDI ID." }) 1424 ] }), 1425 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap gap-2 shrink-0", children: [ 1426 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1427 "button", 1428 { 1429 onClick: applyExpressPreset, 1430 disabled: isSaving, 1431 className: "flex items-center gap-1.5 px-3 py-1.5 bg-amber-500 hover:bg-amber-600 text-white text-[10px] font-black uppercase rounded shadow-sm transition-all disabled:opacity-50", 1432 children: [
1433 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { size: 12 }), 1434 "Set Express Mode" 1435 ] 1436 } 1437 ), 1438 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1439 "button", 1440 { 1441 onClick: applyFullPreset, 1442 disabled: isSaving, 1443 className: "flex items-center gap-1.5 px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white text-[10px] font-black uppercase rounded shadow-sm transition-all disabled:opacity-50", 1444 children: [ 1445 /* @__PURE__ */ jsxRuntimeExports.jsx(Workflow, { size: 12 }), 1446 "Set Full Mode" 1447 ] 1448 } 1449 ) 1450 ] }) 1451 ] }), 1452 backfillStats ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [ 1453 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4", children: [ 1454 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-50 dark:bg-zinc-800/30 p-3.5 rounded-xl border border-zinc-200/50 dark:border-zinc-800 text-center", children: [
1455 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Total Completed (Playback)" }), 1456 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-zinc-800 dark:text-zinc-100 leading-tight", children: backfillStats.totalCompleted.toLocaleString() }) 1457 ] }), 1458 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-50 dark:bg-zinc-800/30 p-3.5 rounded-xl border border-zinc-200/50 dark:border-zinc-800 text-center", children: [ 1459 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 mb-1", children: "With Sheet Music" }), 1460 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-emerald-600 dark:text-emerald-400 leading-tight", children: backfillStats.completedWithSheets.toLocaleString() }) 1461 ] }), 1462 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-50 dark:bg-zinc-800/30 p-3.5 rounded-xl border border-zinc-200/50 dark:border-zinc-800 text-center", children: [
1463 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Pending Sheet Engraving" }), 1464 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-amber-600 dark:text-amber-400 leading-tight", children: backfillStats.backlogCount.toLocaleString() }) 1465 ] }), 1466 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-50 dark:bg-zinc-800/30 p-3.5 rounded-xl border border-zinc-200/50 dark:border-zinc-800 text-center", children: [ 1467 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Backfill Completion" }), 1468 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xl font-black text-indigo-600 dark:text-indigo-400 leading-tight", children: backfillStats.totalCompleted > 0 ? `${Math.round(backfillStats.completedWithSheets / backfillStats.totalCompleted * 100)}%` : "0%" }) 1469 ] }) 1470 ] }),
1471 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [ 1472 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[11px] font-bold text-zinc-500", children: [ 1473 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Sequenced Sheet Music & Stems Completion" }), 1474 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono", children: [ 1475 backfillStats.completedWithSheets.toLocaleString(), 1476 " / ", 1477 backfillStats.totalCompleted.toLocaleString(), 1478 " Tracks" 1479 ] }) 1480 ] }), 1481 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-zinc-100 dark:bg-zinc-800 h-3 rounded-full overflow-hidden shadow-inner border border-zinc-200/40 dark:border-zinc-800", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 1482 "div", 1483 { 1484 className: "bg-gradient-to-r from-indigo-500 to-purple-600 h-full rounded-full transition-all duration-700 ease-out", 1485 style: { width: `${backfillStats.totalCompleted > 0 ? backfillStats.completedWithSheets / backfillStats.totalCompleted * 100 : 0}%` } 1486 } 1487 ) }) 1488 ] }),
1489 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-indigo-50/20 dark:bg-indigo-950/10 border border-indigo-100 dark:border-indigo-950/20 rounded-xl flex flex-col md:flex-row items-center justify-between gap-4", children: [ 1490 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-3 w-full md:w-auto", children: [ 1491 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-2 bg-indigo-100 dark:bg-indigo-900/40 text-indigo-600 dark:text-indigo-400 rounded-lg animate-pulse shrink-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 18 }) }), 1492 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "min-w-0 flex-1", children: [ 1493 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 tracking-wider", children: "Active Worker Engraving Target" }), 1494 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-800 dark:text-zinc-200 mt-0.5", children: backfillStats.currentProcessingId ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1.5 min-w-0", children: [
1495 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-1.5 py-0.5 bg-indigo-100 dark:bg-indigo-900/60 border border-indigo-200 dark:border-indigo-800 text-indigo-700 dark:text-indigo-300 text-[10px] font-mono font-black rounded shrink-0", children: [ 1496 "ID #", 1497 backfillStats.currentProcessingId 1498 ] }), 1499 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate max-w-[200px] md:max-w-xs block", children: backfillStats.currentProcessingTitle || "Processing files..." }) 1500 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400 italic", children: "No active engravings. Worker is idle or processing non-engraving tasks." }) }) 1501 ] }) 1502 ] }), 1503 /* @__PURE__ */ jsxRuntimeExports.jsx( 1504 "button", 1505 { 1506 onClick: () => { 1507 var _a2; 1508 setBulkStartId("1"); 1509 setBulkEndId(String(backfillStats.totalCompleted)); 1510 setBulkFullProcess(false); 1511 setBulkSteps(config.enabledSteps && config.enabledSteps.length > 0 ? config.enabledSteps : pipelineSteps.map((s) => s.slug)); 1512 setIsConfigured(true); 1513 setTimeout(() => setIsConfigured(false), 3e3); 1514 const bulkCard = (_a2 = document.querySelector('h3:has(svg:has([class*="RefreshCw"]))')) == null ? void 0 : _a2.closest(".bg-white"); 1515 if (bulkCard) { 1516 bulkCard.scrollIntoView({ behavior: "smooth" }); 1517 } else { 1518 window.scrollTo({ top: document.body.scrollHeight, behavior: "smooth" }); 1519 } 1520 }, 1521 className: `w-full md:w-auto px-4 py-2 rounded-xl text-xs font-bold flex items-center justify-center gap-2 transition-all shrink-0 shadow-sm ${isConfigured ? "bg-emerald-600 hover:bg-emerald-700 text-white shadow-emerald-650/20 scale-105" : "bg-indigo-600 hover:bg-indigo-700 text-white shadow-indigo-600/10"}`, 1522 children: isConfigured ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
1523 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { size: 14, className: "animate-bounce" }), 1524 "Range Configured (1 - ", 1525 backfillStats.totalCompleted, 1526 ")" 1527 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 1528 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 14 }), 1529 "Auto-Configure Backfill Range" 1530 ] }) 1531 } 1532 ) 1533 ] }) 1534 ] }) : backfillError ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "py-10 text-center space-y-3", children: [ 1535 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-bold text-red-500 dark:text-red-400", children: "Failed to load backfill telemetry statistics" }), 1536 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs text-zinc-500 dark:text-zinc-400 max-w-md mx-auto", children: backfillError }), 1537 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1538 "button", 1539 { 1540 onClick: () => fetchBackfillStats(true), 1541 className: "px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-xs font-bold transition inline-flex items-center gap-1.5 shadow-sm", 1542 children: [
1543 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 13 }), 1544 " Retry Loading" 1545 ] 1546 } 1547 ) 1548 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "py-12 text-center", children: [ 1549 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin mx-auto text-zinc-300 mb-2", size: 24 }), 1550 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400 font-bold", children: "Loading backfill telemetry statistics..." }) 1551 ] }) 1552 ] }), 1553 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col lg:flex-row gap-6", children: [ 1554 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "lg:w-3/4 flex flex-col gap-6", children: [ 1555 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-red-200 dark:border-red-950/60 rounded-xl p-6 shadow-sm", children: [ 1556 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4 mb-4 border-b border-zinc-100 dark:border-zinc-800 pb-4", children: [
1557 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1558 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-black uppercase text-red-600 dark:text-red-400 flex items-center gap-2", children: [ 1559 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { size: 20, className: "text-red-500 animate-pulse" }), 1560 " Persistent Processing Failures" 1561 ] }), 1562 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 mt-1", children: "Errors caught during worker ingestion and audio synthesis. These are saved persistently in shared storage and will not be cleared by DB Resets until successfully re-processed or dismissed." }) 1563 ] }), 1564 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "shrink-0 flex items-center gap-2", children: [ 1565 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `text-[10px] font-extrabold px-2.5 py-1 rounded-md border shadow-sm ${persistentErrors.length > 0 ? "bg-red-50 dark:bg-red-950/40 text-red-600 dark:text-red-400 border-red-200 dark:border-red-900/50" : "bg-emerald-50 dark:bg-emerald-950/40 text-emerald-600 dark:text-emerald-400 border-emerald-200 dark:border-emerald-900/50"}`, children: [ 1566 persistentErrors.length, 1567 " Failure", 1568 persistentErrors.length !== 1 ? "s" : "", 1569 " Record" 1570 ] }),
1571 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1572 "button", 1573 { 1574 onClick: () => setAutoRefreshErrors(!autoRefreshErrors), 1575 className: `px-2.5 py-1.5 rounded-lg text-[10px] font-bold flex items-center gap-1.5 transition-all border ${autoRefreshErrors ? "bg-emerald-50 dark:bg-emerald-950/20 border-emerald-250 dark:border-emerald-900/50 text-emerald-600 dark:text-emerald-400 hover:bg-emerald-100/50 shadow-sm" : "bg-zinc-50 dark:bg-zinc-800 border-zinc-200 dark:border-zinc-700 text-zinc-500 dark:text-zinc-400 hover:bg-zinc-100 dark:hover:bg-zinc-700"}`, 1576 title: autoRefreshErrors ? "Pause Automatic Refresh" : "Enable Automatic Refresh", 1577 children: [ 1578 autoRefreshErrors ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleStop, { size: 12, className: "text-emerald-500 animate-pulse" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CirclePlay, { size: 12 }), 1579 autoRefreshErrors ? "Auto Refresh: Active" : "Auto Refresh: Paused" 1580 ] 1581 } 1582 ),
1583 /* @__PURE__ */ jsxRuntimeExports.jsx( 1584 "button", 1585 { 1586 onClick: fetchPersistentErrors, 1587 disabled: isLoadingErrors, 1588 className: "p-1.5 bg-zinc-50 dark:bg-zinc-800 hover:bg-zinc-100 dark:hover:bg-zinc-700 border border-zinc-200 dark:border-zinc-700 text-zinc-650 dark:text-zinc-400 rounded-lg transition-all", 1589 title: "Refresh Errors Now", 1590 children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 14, className: isLoadingErrors ? "animate-spin" : "" }) 1591 } 1592 ) 1593 ] }) 1594 ] }), 1595 isLoadingErrors && persistentErrors.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "py-8 text-center", children: [ 1596 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin mx-auto text-zinc-300 mb-2", size: 24 }), 1597 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-zinc-400 font-bold", children: "Loading persistent failure records..." }) 1598 ] }) : persistentErrors.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-emerald-100 dark:border-emerald-950/30 bg-emerald-50/25 dark:bg-emerald-950/10 rounded-xl p-6 flex flex-col items-center justify-center py-8", children: [
1599 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { className: "text-emerald-500 mb-2", size: 32 }), 1600 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-emerald-800 dark:text-emerald-400", children: "Zero Persistent Failures!" }), 1601 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-emerald-600 dark:text-emerald-500 mt-1", children: "All worker pipelines are healthy or currently clear of logged persistent exceptions." }) 1602 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border border-zinc-200 dark:border-zinc-800 rounded-xl overflow-hidden divide-y divide-zinc-150 dark:divide-zinc-800 custom-scrollbar max-h-[450px] overflow-y-auto", children: Array.isArray(persistentErrors) && persistentErrors.map((err) => { 1603 const isExpanded = expandedErrorId === err.id; 1604 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "transition-all hover:bg-zinc-50/50 dark:hover:bg-zinc-800/10", children: [
1605 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4", children: [ 1606 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [ 1607 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [ 1608 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 bg-red-100 dark:bg-red-950/60 border border-red-200 dark:border-red-800 text-red-700 dark:text-red-300 text-[10px] font-mono font-black rounded shrink-0", children: [ 1609 "ID #", 1610 err.id 1611 ] }), 1612 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-black text-zinc-800 dark:text-zinc-200 truncate max-w-[200px] md:max-w-xs block", children: err.title || "Untitled MIDI" }), 1613 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] font-mono text-zinc-400 dark:text-zinc-500 font-bold", children: [ 1614 "Failed: ", 1615 new Date(err.timestamp).toLocaleString() 1616 ] }) 1617 ] }),
1618 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[11px] font-bold text-red-500 mt-1.5 flex items-start gap-1.5", children: [ 1619 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 bg-red-500/10 px-1 py-0.5 rounded text-[8px] tracking-tight uppercase font-black", children: "Error" }), 1620 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "break-all", children: err.error }) 1621 ] }) 1622 ] }), 1623 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 shrink-0 w-full sm:w-auto justify-end", children: [ 1624 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1625 "button", 1626 { 1627 onClick: () => setExpandedErrorId(isExpanded ? null : err.id), 1628 className: "px-2.5 py-1.5 bg-zinc-100 dark:bg-zinc-800 hover:bg-zinc-200 dark:hover:bg-zinc-700 border border-zinc-250 dark:border-zinc-750 text-zinc-700 dark:text-zinc-300 rounded-lg text-[10px] font-bold flex items-center gap-1 transition-all", 1629 title: isExpanded ? "Hide details" : "Show full stack trace", 1630 children: [
1631 /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 12 }), 1632 isExpanded ? "Hide Trace" : "View Trace" 1633 ] 1634 } 1635 ), 1636 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1637 "button", 1638 { 1639 onClick: () => handleReprocessError(err.id), 1640 className: "px-3 py-1.5 bg-indigo-650 hover:bg-indigo-700 text-white rounded-lg text-[10px] font-bold flex items-center gap-1 transition-all shadow-sm", 1641 title: "Queue for reprocessing immediately", 1642 children: [ 1643 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 12 }), 1644 "Reprocess" 1645 ] 1646 } 1647 ), 1648 /* @__PURE__ */ jsxRuntimeExports.jsx( 1649 "button", 1650 { 1651 onClick: () => handleDismissError(err.id), 1652 className: "p-1.5 bg-red-50 hover:bg-red-100 dark:bg-red-950/20 dark:hover:bg-red-900/40 text-red-650 rounded-lg transition-colors border border-red-100/50 dark:border-red-950/40", 1653 title: "Dismiss/Delete error record", 1654 children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 13 }) 1655 } 1656 ) 1657 ] }) 1658 ] }),
1659 isExpanded && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pb-4 border-t border-dashed border-zinc-150 dark:border-zinc-800/80 bg-zinc-50/50 dark:bg-zinc-950/20 pt-3", children: [ 1660 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[9px] font-black uppercase text-zinc-400 mb-1.5 tracking-wider", children: "Detailed Execution Traceback" }), 1661 /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "p-3 bg-[#0a0a0a] border border-zinc-200 dark:border-zinc-800 rounded-lg font-mono text-[9px] text-zinc-400 overflow-x-auto whitespace-pre leading-relaxed custom-scrollbar max-h-[250px]", children: err.details || "No further details available." }) 1662 ] }) 1663 ] }, err.id); 1664 }) }) }) 1665 ] }), 1666 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-[#111] dark:bg-black rounded-xl p-0 overflow-hidden flex flex-col h-[calc(100vh-280px)] min-h-[400px] border border-zinc-200 dark:border-zinc-800 shadow-xl resize-y", children: [
1667 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-100 dark:bg-zinc-900 border-b border-zinc-200 dark:border-zinc-800 flex justify-between items-center shrink-0", children: [ 1668 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 text-zinc-900 dark:text-white font-black uppercase text-xs", children: [ 1669 /* @__PURE__ */ jsxRuntimeExports.jsx(Terminal, { size: 16, className: "text-indigo-500" }), 1670 " Live Worker Output", 1671 Array.isArray(instances) && instances.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs( 1672 "select", 1673 { 1674 value: selectedInstance, 1675 onChange: (e) => setSelectedInstance(e.target.value), 1676 className: "ml-3 px-2.5 py-1 bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg text-[10px] font-bold text-zinc-700 dark:text-zinc-300 focus:outline-none focus:ring-1 focus:ring-indigo-500 cursor-pointer", 1677 children: [
1678 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "unified", children: "Unified (All Workers)" }), 1679 (() => { 1680 const grouped = {}; 1681 instances.forEach((inst) => { 1682 const node = getNodeForInstance(inst); 1683 if (!grouped[node.id]) { 1684 grouped[node.id] = { name: node.name, list: [] }; 1685 } 1686 grouped[node.id].list.push(inst); 1687 }); 1688 return Object.keys(grouped).map((nodeIdKey) => { 1689 const nodeId = Number(nodeIdKey); 1690 const group = grouped[nodeId]; 1691 return /* @__PURE__ */ jsxRuntimeExports.jsx("optgroup", { label: group.name, className: "bg-white dark:bg-zinc-800 text-zinc-800 dark:text-zinc-200 font-bold", children: group.list.map((inst) => /* @__PURE__ */ jsxRuntimeExports.jsxs("option", { value: inst.pid, className: "font-normal text-xs", children: [ 1692 formatPidDisplay(inst.pid), 1693 " (", 1694 inst.elapsed || "Active", 1695 ")" 1696 ] }, inst.pid)) }, nodeId); 1697 }); 1698 })() 1699 ] 1700 } 1701 ) 1702 ] }),
1703 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 1704 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex bg-zinc-200 dark:bg-zinc-800 p-0.5 rounded-lg mr-2", children: [ 1705 /* @__PURE__ */ jsxRuntimeExports.jsx( 1706 "button", 1707 { 1708 onClick: () => setViewMode("terminal"), 1709 className: `px-2.5 py-1 text-[9px] font-black uppercase rounded transition-all ${viewMode === "terminal" ? "bg-white dark:bg-zinc-900 text-indigo-650 dark:text-indigo-400 shadow-sm" : "text-zinc-500 dark:text-zinc-400 hover:text-zinc-800 dark:hover:text-zinc-200"}`, 1710 children: "Terminal" 1711 } 1712 ), 1713 /* @__PURE__ */ jsxRuntimeExports.jsx( 1714 "button", 1715 { 1716 onClick: () => setViewMode("grid"), 1717 className: `px-2.5 py-1 text-[9px] font-black uppercase rounded transition-all ${viewMode === "grid" ? "bg-white dark:bg-zinc-900 text-indigo-650 dark:text-indigo-400 shadow-sm" : "text-zinc-500 dark:text-zinc-400 hover:text-zinc-800 dark:hover:text-zinc-200"}`, 1718 children: "Visual Grid" 1719 } 1720 ) 1721 ] }),
1722 /* @__PURE__ */ jsxRuntimeExports.jsx( 1723 "button", 1724 { 1725 onClick: () => setAutoScroll(!autoScroll), 1726 className: `flex items-center gap-1.5 px-2.5 py-1 text-[10px] font-black uppercase rounded transition-all mr-1 ${autoScroll ? "bg-indigo-500 hover:bg-indigo-600 text-white shadow-sm shadow-indigo-500/20" : "bg-zinc-200 dark:bg-zinc-800 hover:bg-zinc-300 dark:hover:bg-zinc-700 text-zinc-600 dark:text-zinc-400"}`, 1727 title: autoScroll ? "Disable Auto-Scroll" : "Enable Auto-Scroll", 1728 children: autoScroll ? "Auto-scroll: ON" : "Auto-scroll: OFF" 1729 } 1730 ), 1731 selectedInstance === "unified" && /* @__PURE__ */ jsxRuntimeExports.jsxs( 1732 "button", 1733 { 1734 onClick: handleClearLogs, 1735 className: "flex items-center gap-1.5 px-2 py-1 bg-zinc-200 dark:bg-zinc-800 hover:bg-zinc-300 dark:hover:bg-zinc-700 text-zinc-600 dark:text-zinc-400 text-[10px] font-black uppercase rounded transition-colors mr-2", 1736 title: "Clear Log File", 1737 children: [
1738 /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { size: 12 }), 1739 "Clear" 1740 ] 1741 } 1742 ), 1743 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-2 h-2 rounded-full ${autoScroll ? "bg-emerald-500 animate-pulse" : "bg-amber-500"}` }), 1744 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold uppercase tracking-widest ${autoScroll ? "text-zinc-500 dark:text-emerald-500" : "text-amber-500"}`, children: autoScroll ? "Streaming" : "Paused" }) 1745 ] }) 1746 ] }), 1747 viewMode === "terminal" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 1748 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: logContainerRef, className: "p-6 overflow-y-auto font-mono text-[11px] text-zinc-400 bg-black/50 dark:bg-black/20 space-y-1 h-full custom-scrollbar leading-relaxed", children: logs.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col items-center justify-center opacity-30", children: [
1749 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin mb-2", size: 32 }), 1750 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-sm", children: "Initializing log stream..." }) 1751 ] }) : logs.map((log, i) => /* @__PURE__ */ jsxRuntimeExports.jsx(LogLine, { index: i, log }, i)) }), 1752 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-2 px-6 bg-zinc-50 dark:bg-zinc-900/50 border-t border-zinc-200 dark:border-zinc-800 flex justify-between items-center shrink-0", children: [ 1753 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-zinc-400 font-bold", children: [ 1754 "Total entries: ", 1755 logs.length 1756 ] }), 1757 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-400 italic", children: autoScroll ? "Turn OFF auto-scroll to freeze log stream and read comfortably" : "Auto-scroll is paused. Turn ON to resume tracking newest logs" }) 1758 ] }) 1759 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-6 overflow-y-auto bg-zinc-50 dark:bg-zinc-950 flex-1 space-y-6 custom-scrollbar h-full", children: workerNodes.map((node) => { 1760 const nodeWorkers = Array.isArray(node.activeWorkers) ? node.activeWorkers : []; 1761 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-zinc-200/60 dark:border-zinc-800/65 pb-4 last:border-0 last:pb-0", children: [
1762 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-between mb-3", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-[11px] font-black uppercase text-zinc-500 dark:text-zinc-450 tracking-wider flex items-center gap-1.5", children: [ 1763 /* @__PURE__ */ jsxRuntimeExports.jsx(Cpu, { size: 12, className: "text-indigo-500" }), 1764 node.name, 1765 " ", 1766 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] lowercase font-normal text-zinc-400", children: [ 1767 "(", 1768 nodeWorkers.length, 1769 " active worker", 1770 nodeWorkers.length !== 1 ? "s" : "", 1771 ")" 1772 ] }) 1773 ] }) }), 1774 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-3", children: nodeWorkers.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-400 italic py-2 pl-1", children: "No active workers online." }) : nodeWorkers.map((worker) => { 1775 const activeTask = worker.activeTasks && worker.activeTasks[0]; 1776 const isProcessing = !!activeTask; 1777 let stepText = "idle"; 1778 let progressPercent = 0; 1779 let stepTextDisplay = "0/0"; 1780 let tooltipText = `Worker UUID: ${worker.uuid} 1781State: Idle`; 1782 if (isProcessing) { 1783 const statusStr = activeTask.status || ""; 1784 tooltipText = `Worker UUID: ${worker.uuid} 1785Task ID: #${activeTask.id} 1786Title: ${activeTask.title} 1787State: ${statusStr}`; 1788 const stepMatch = statusStr.match(/Step\s+(\d+)\/(\d+)/i); 1789 if (stepMatch) { 1790 const currentStep = parseInt(stepMatch[1]); 1791 const totalSteps = parseInt(stepMatch[2]); 1792 stepTextDisplay = `${currentStep}/${totalSteps}`; 1793 progressPercent = Math.min(100, Math.round(currentStep / totalSteps * 100)); 1794 stepText = statusStr.replace(/Step\s+\d+\/\d+:\s*/i, ""); 1795 } else { 1796 stepTextDisplay = "actv"; 1797 stepText = statusStr || "processing"; 1798 progressPercent = 100; 1799 } 1800 } 1801 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 1802 "div", 1803 { 1804 onClick: () => { 1805 if (worker.pid) { 1806 setSelectedInstance(worker.pid); 1807 setViewMode("terminal"); 1808 } else { 1809 alert("Logs are not available for this worker (no active container association found)."); 1810 } 1811 }, 1812 className: `w-28 h-28 bg-white dark:bg-zinc-900 border rounded-xl p-3 flex flex-col justify-between cursor-pointer transition-all select-none hover:scale-[1.02] active:scale-[0.98] group relative ${isProcessing ? "border-indigo-200 hover:border-indigo-400 dark:border-indigo-950/60 dark:hover:border-indigo-800 shadow-sm shadow-indigo-500/5" : "border-zinc-200 hover:border-zinc-350 dark:border-zinc-800/80 dark:hover:border-zinc-700"}`, 1813 title: tooltipText, 1814 children: [
1815 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center w-full", children: [ 1816 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-[9px] font-bold text-zinc-400 dark:text-zinc-500", children: [ 1817 "#", 1818 worker.uuid 1819 ] }), 1820 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `w-1.5 h-1.5 rounded-full ${isProcessing ? "bg-indigo-500 animate-pulse" : "bg-emerald-500"}` }) 1821 ] }), 1822 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center my-1.5", children: [ 1823 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-mono text-xl font-black ${isProcessing ? "text-indigo-650 dark:text-indigo-400" : "text-zinc-350 dark:text-zinc-650"}`, children: stepTextDisplay }), 1824 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[7px] font-bold uppercase tracking-wider text-zinc-400 dark:text-zinc-500 mt-0.5 truncate max-w-full", children: isProcessing ? `midi #${activeTask.id || "?"}` : "idle" }) 1825 ] }),
1826 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full", children: [ 1827 isProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-zinc-100 dark:bg-zinc-800 h-1 rounded-full overflow-hidden mb-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 1828 "div", 1829 { 1830 className: "bg-indigo-600 h-full rounded-full transition-all duration-300", 1831 style: { width: `${progressPercent}%` } 1832 } 1833 ) }) : null, 1834 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[7px] text-zinc-400 dark:text-zinc-500 font-mono", children: [ 1835 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1836 "CPU: ", 1837 worker.cpu, 1838 "%" 1839 ] }),
1840 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1841 "RAM: ", 1842 worker.ram, 1843 "%" 1844 ] }) 1845 ] }) 1846 ] }), 1847 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute inset-0 bg-black/90 dark:bg-black/95 rounded-xl opacity-0 group-hover:opacity-100 transition-opacity p-2 flex flex-col justify-between text-[8px] text-zinc-300 pointer-events-none z-10", children: [ 1848 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1", children: [ 1849 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-bold text-zinc-100 flex justify-between border-b border-zinc-800 pb-1 mb-1", children: [ 1850 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 1851 "Worker #", 1852 worker.uuid 1853 ] }),
1854 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: isProcessing ? "text-indigo-400 animate-pulse" : "text-emerald-400", children: isProcessing ? "Busy" : "Idle" }) 1855 ] }), 1856 isProcessing && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 1857 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "truncate text-white font-black", children: [ 1858 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-500 font-normal", children: "Midi:" }), 1859 " #", 1860 activeTask.id 1861 ] }), 1862 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "line-clamp-2 text-zinc-300 font-bold leading-tight", children: activeTask.title }), 1863 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-indigo-455 dark:text-indigo-400 font-bold border-t border-zinc-800/80 pt-1 mt-1 leading-normal line-clamp-2", children: [ 1864 stepTextDisplay, 1865 ": ", 1866 stepText 1867 ] }) 1868 ] }) 1869 ] }),
1870 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[7px] text-zinc-500 border-t border-zinc-800 pt-1", children: "Click to view live logs" }) 1871 ] }) 1872 ] 1873 }, 1874 worker.uuid 1875 ); 1876 }) }) 1877 ] }, node.id); 1878 }) }) 1879 ] }), 1880 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [ 1881 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col xl:flex-row xl:items-center justify-between gap-4 mb-4 border-b border-zinc-100 dark:border-zinc-800 pb-4", children: [ 1882 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1883 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-black uppercase text-zinc-900 dark:text-white flex items-center gap-2", children: [ 1884 /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { size: 20, className: "text-indigo-500" }), 1885 " Storage Assets Integrity Check" 1886 ] }),
1887 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 mt-1", children: "Scan completed tracks on physical storage to verify if all corresponding MIDI, audio, high/low-res Opus, waveforms, piano rolls, and animated thumbnails exist." }) 1888 ] }), 1889 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-wrap items-center gap-3 shrink-0", children: [ 1890 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 bg-zinc-50 dark:bg-zinc-800/30 border border-zinc-200/60 dark:border-zinc-800 px-2 py-1 rounded-lg", children: [ 1891 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-black text-zinc-400 uppercase tracking-wider", children: "ID Range:" }), 1892 /* @__PURE__ */ jsxRuntimeExports.jsx( 1893 "input", 1894 { 1895 type: "number", 1896 placeholder: "Start ID", 1897 value: integrityStartId, 1898 onChange: (e) => setIntegrityStartId(e.target.value), 1899 className: "w-20 px-2 py-1 text-xs bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-800 dark:text-zinc-100 focus:outline-none focus:ring-1 focus:ring-indigo-500 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none text-center font-bold" 1900 } 1901 ),
1902 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-bold text-zinc-400", children: "â" }), 1903 /* @__PURE__ */ jsxRuntimeExports.jsx( 1904 "input", 1905 { 1906 type: "number", 1907 placeholder: "End ID", 1908 value: integrityEndId, 1909 onChange: (e) => setIntegrityEndId(e.target.value), 1910 className: "w-20 px-2 py-1 text-xs bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-800 dark:text-zinc-100 focus:outline-none focus:ring-1 focus:ring-indigo-500 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none text-center font-bold" 1911 } 1912 ) 1913 ] }), 1914 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1915 "button", 1916 { 1917 onClick: handleRunIntegrityCheck, 1918 disabled: isCheckingIntegrity, 1919 className: "px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-xs font-bold shadow-sm flex items-center justify-center gap-2 transition-all disabled:opacity-50", 1920 children: [ 1921 isCheckingIntegrity ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 14 }), 1922 isCheckingIntegrity ? "Scanning Disk..." : "Run Storage Integrity Check" 1923 ] 1924 } 1925 ) 1926 ] }) 1927 ] }), 1928 isCheckingIntegrity && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-indigo-100 dark:border-indigo-950/30 bg-indigo-50/20 dark:bg-indigo-950/10 rounded-xl p-6 flex flex-col items-center justify-center py-10", children: [
1929 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin text-indigo-500 mb-2", size: 24 }), 1930 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-indigo-700 dark:text-indigo-400", children: "Verifying database records against physical storage files..." }), 1931 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-indigo-500 mt-1", children: "This might take several seconds depending on your database size." }) 1932 ] }), 1933 (bgQueueStatus == null ? void 0 : bgQueueStatus.isRunning) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6 p-4 bg-indigo-50/50 dark:bg-indigo-950/10 border border-indigo-150 dark:border-indigo-900/30 rounded-xl", children: [ 1934 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-4 mb-2", children: [ 1935 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
1936 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "animate-spin text-indigo-500", size: 18 }), 1937 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-black text-indigo-900 dark:text-indigo-400", children: "Background Queueing Job Active" }) 1938 ] }), 1939 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 font-bold", children: [ 1940 bgQueueStatus.processedCount.toLocaleString(), 1941 " / ", 1942 bgQueueStatus.totalToScan.toLocaleString(), 1943 " Scanned" 1944 ] }) 1945 ] }), 1946 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-zinc-200 dark:bg-zinc-800/60 h-2 rounded-full overflow-hidden mb-3", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 1947 "div", 1948 { 1949 className: "bg-indigo-600 h-full rounded-full transition-all duration-300", 1950 style: { width: `${bgQueueStatus.totalToScan > 0 ? bgQueueStatus.processedCount / bgQueueStatus.totalToScan * 100 : 0}%` } 1951 } 1952 ) }),
1953 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-3 gap-2 text-center text-[10px] text-zinc-650 dark:text-zinc-400 border-t border-indigo-100/40 dark:border-indigo-900/20 pt-2 font-black uppercase", children: [ 1954 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1955 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-indigo-600 dark:text-indigo-400 block text-xs font-black", children: bgQueueStatus.queuedCount.toLocaleString() }), 1956 "Queued to Rebuild" 1957 ] }), 1958 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-l border-indigo-100/40 dark:border-indigo-900/20", children: [ 1959 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-amber-600 dark:text-amber-400 block text-xs font-black", children: bgQueueStatus.markedMissingCount.toLocaleString() }), 1960 "Marked as Missing" 1961 ] }), 1962 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-l border-indigo-100/40 dark:border-indigo-900/20", children: [
1963 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-zinc-650 dark:text-zinc-450 block text-xs font-mono font-bold", children: [ 1964 "#", 1965 bgQueueStatus.currentId || "N/A" 1966 ] }), 1967 "Current Track ID" 1968 ] }) 1969 ] }) 1970 ] }), 1971 !(bgQueueStatus == null ? void 0 : bgQueueStatus.isRunning) && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6 p-4 bg-amber-500/10 dark:bg-amber-500/5 border border-amber-500/20 dark:border-amber-500/10 rounded-xl flex flex-col gap-4", children: [ 1972 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start gap-3", children: [ 1973 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { className: "text-amber-600 dark:text-amber-400 shrink-0 mt-0.5", size: 18 }), 1974 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1975 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-black text-zinc-900 dark:text-white", children: "Storage Sync & Missing File Requeue" }),
1976 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 mt-0.5", children: "Scan the database and disk files in the background to automatically identify missing files, sync DB state, and optionally requeue tracks to rebuild them." }) 1977 ] }) 1978 ] }), 1979 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 bg-white dark:bg-zinc-800/40 border border-zinc-200 dark:border-zinc-700/50 p-4 rounded-lg", children: [ 1980 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 1981 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] font-bold text-zinc-600 dark:text-zinc-400 block mb-1", children: "Scan Target" }), 1982 /* @__PURE__ */ jsxRuntimeExports.jsxs( 1983 "select", 1984 { 1985 value: integrityScanMode, 1986 onChange: (e) => setIntegrityScanMode(e.target.value), 1987 className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100", 1988 children: [
1989 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "idRange", children: "By ID Range" }), 1990 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "singleId", children: "By Single Track ID" }), 1991 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "dateRange", children: "By Date Range" }), 1992 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "status", children: "By Database Status" }), 1993 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "specificFileMissing", children: "Tracks Missing Specific File" }), 1994 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "all", children: "ALL Active Tracks" }) 1995 ] 1996 } 1997 ) 1998 ] }), 1999 integrityScanMode === "idRange" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-end gap-2", children: [ 2000 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [
2001 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] font-bold text-zinc-600 dark:text-zinc-400 block mb-1", children: "Start ID" }), 2002 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: integrityStartId, onChange: (e) => setIntegrityStartId(e.target.value), placeholder: "e.g. 1", className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100" }) 2003 ] }), 2004 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1", children: [ 2005 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] font-bold text-zinc-600 dark:text-zinc-400 block mb-1", children: "End ID" }), 2006 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: integrityEndId, onChange: (e) => setIntegrityEndId(e.target.value), placeholder: "Optional", className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100" }) 2007 ] }) 2008 ] }), 2009 integrityScanMode === "singleId" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
2010 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] font-bold text-zinc-600 dark:text-zinc-400 block mb-1", children: "Track ID" }), 2011 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "number", value: integritySingleId, onChange: (e) => setIntegritySingleId(e.target.value), placeholder: "e.g. 12345", className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100" }) 2012 ] }), 2013 integrityScanMode === "dateRange" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [ 2014 /* @__PURE__ */ jsxRuntimeExports.jsxs("select", { value: integrityDateField, onChange: (e) => setIntegrityDateField(e.target.value), className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100", children: [ 2015 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "lastProcessedAt", children: "Last Processed At" }),
2016 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "createdAt", children: "Created At" }) 2017 ] }), 2018 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 2019 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "date", value: integrityStartDate, onChange: (e) => setIntegrityStartDate(e.target.value), className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100" }), 2020 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400 font-bold", children: "â" }), 2021 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "date", value: integrityEndDate, onChange: (e) => setIntegrityEndDate(e.target.value), className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100" }) 2022 ] }) 2023 ] }), 2024 integrityScanMode === "status" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
2025 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] font-bold text-zinc-600 dark:text-zinc-400 block mb-1", children: "Database Status" }), 2026 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "text", value: integrityStatusFilter, onChange: (e) => setIntegrityStatusFilter(e.target.value), placeholder: "e.g. completed, pending, metadata_only", className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100" }) 2027 ] }), 2028 integrityScanMode === "specificFileMissing" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2029 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] font-bold text-zinc-600 dark:text-zinc-400 block mb-1", children: "File Key in generatedFiles" }), 2030 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "text", value: integrityMissingFile, onChange: (e) => setIntegrityMissingFile(e.target.value), placeholder: "e.g. highOpus, pianoRollJson", className: "w-full text-xs p-2 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-md text-zinc-900 dark:text-zinc-100" }) 2031 ] }) 2032 ] }),
2033 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between bg-zinc-50 dark:bg-zinc-900/50 p-3 rounded-lg border border-zinc-200 dark:border-zinc-800", children: [ 2034 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2035 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs font-bold text-zinc-900 dark:text-zinc-100", children: "Requeue Missing Files" }), 2036 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-zinc-500", children: "If checked, tracks with missing files (excluding metadata_only) will be put into the queue to rebuild." }) 2037 ] }), 2038 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "relative inline-flex items-center cursor-pointer", children: [ 2039 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", className: "sr-only peer", checked: integrityRequeueMissing, onChange: (e) => setIntegrityRequeueMissing(e.target.checked) }),
2040 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-9 h-5 bg-zinc-300 peer-focus:outline-none rounded-full peer dark:bg-zinc-700 peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-zinc-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-zinc-600 peer-checked:bg-indigo-500" }) 2041 ] }) 2042 ] }), 2043 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-end", children: /* @__PURE__ */ jsxRuntimeExports.jsxs( 2044 "button", 2045 { 2046 onClick: handleQueueAllUnhealthy, 2047 disabled: isReprocessing || isCheckingIntegrity, 2048 className: "px-4 py-2 bg-amber-600 hover:bg-amber-700 text-white rounded-xl text-xs font-black flex items-center justify-center gap-2 transition-all disabled:opacity-50 shadow-sm shrink-0", 2049 children: [ 2050 isReprocessing ? /* @__P
2050URE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CirclePlay, { size: 14 }), 2051 "Run Sync & Queue" 2052 ] 2053 } 2054 ) }) 2055 ] }), 2056 !isCheckingIntegrity && integrityResult && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-6 space-y-6", children: [ 2057 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-4 p-4 bg-zinc-50 dark:bg-zinc-800/20 rounded-xl border border-zinc-100 dark:border-zinc-800/50", children: [ 2058 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center", children: [ 2059 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Total Tracks Scanned" }), 2060 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-black text-zinc-800 dark:text-zinc-200", children: integrityResult.totalScanned }) 2061 ] }),
2062 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center border-l border-zinc-100 dark:border-zinc-800/50", children: [ 2063 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Total File Size" }), 2064 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-black text-indigo-600 dark:text-indigo-400", children: formatBytes(integrityResult.totalSizeSumBytes) }) 2065 ] }), 2066 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center border-l border-zinc-100 dark:border-zinc-800/50", children: [ 2067 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Healthy" }), 2068 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-sm font-black text-emerald-600 flex items-center justify-center gap-1", children: [ 2069 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { size: 14 }), 2070 " ", 2071 integrityResult.healthyCount 2072 ] }) 2073 ] }),
2074 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-center border-l border-zinc-100 dark:border-zinc-800/50", children: [ 2075 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Unhealthy" }), 2076 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `text-sm font-black flex items-center justify-center gap-1 ${integrityResult.unhealthyCount > 0 ? "text-red-500 animate-pulse" : "text-zinc-500"}`, children: [ 2077 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { size: 14 }), 2078 " ", 2079 integrityResult.unhealthyCount 2080 ] }) 2081 ] }) 2082 ] }), 2083 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex border-b border-zinc-150 dark:border-zinc-800 gap-1.5 mt-6 mb-4", children: [ 2084 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2085 "button", 2086 { 2087 onClick: () => setIntegrityTab("list"), 2088 className: `pb-2.5 px-4 text-xs font-bold border-b-2 transition-all ${integrityTab === "list" ? "border-indigo-500 text-indigo-600 dark:text-indigo-400 font-black" : "border-transparent text-zinc-400 hover:text-zinc-650"}`, 2089 children: [ 2090 "Unhealthy List (", 2091 integrityResult.unhealthyCount, 2092 ")" 2093 ] 2094 } 2095 ),
2096 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2097 "button", 2098 { 2099 onClick: () => setIntegrityTab("map"), 2100 className: `pb-2.5 px-4 text-xs font-bold border-b-2 transition-all ${integrityTab === "map" ? "border-indigo-500 text-indigo-600 dark:text-indigo-400 font-black" : "border-transparent text-zinc-400 hover:text-zinc-650"}`, 2101 children: [ 2102 "Visual Asset Map (", 2103 mapTracks.length, 2104 ")" 2105 ] 2106 } 2107 ) 2108 ] }), 2109 integrityTab === "list" ? ( 2110 /* Unhealthy Tracks List */ 2111 integrityResult.unhealthyCount > 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ 2112 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [ 2113 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-300", children: [ 2114 "Unhealthy Tracks Found (", 2115 integrityResult.unhealthyCount, 2116 ")" 2117 ] }),
2118 /* @__PURE__ */ jsxRuntimeExports.jsx( 2119 "button", 2120 { 2121 onClick: handleToggleSelectAllUnhealthy, 2122 className: "text-[10px] font-bold text-indigo-600 hover:text-indigo-700 uppercase", 2123 children: selectedUnhealthyIds.length === (integrityResult.unhealthyTracks || []).length ? "Deselect All" : "Select All" 2124 } 2125 ) 2126 ] }), 2127 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "border border-zinc-100 dark:border-zinc-800 rounded-xl max-h-[300px] overflow-y-auto divide-y divide-zinc-100 dark:divide-zinc-800 custom-scrollbar", children: (integrityResult.unhealthyTracks || []).map((track) => { 2128 const isSelected = selectedUnhealthyIds.includes(track.id); 2129 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 2130 "div", 2131 { 2132 onClick: () => handleToggleSelectUnhealthy(track.id), 2133 className: `p-3.5 flex items-start gap-3 cursor-pointer hover:bg-zinc-50 dark:hover:bg-zinc-800/10 transition-colors ${isSelected ? "bg-indigo-50/20 dark:bg-indigo-950/10" : ""}`, 2134 children: [
2135 /* @__PURE__ */ jsxRuntimeExports.jsx( 2136 "input", 2137 { 2138 type: "checkbox", 2139 checked: isSelected, 2140 onChange: () => { 2141 }, 2142 className: "mt-1 rounded border-zinc-300 dark:border-zinc-700 text-indigo-600 focus:ring-indigo-500 h-4 w-4 shrink-0" 2143 } 2144 ), 2145 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-w-0", children: [ 2146 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between gap-2", children: [ 2147 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-xs font-bold text-zinc-900 dark:text-white truncate flex items-center gap-1.5 flex-wrap", children: [ 2148 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 2149 "#", 2150 track.id, 2151 " - ", 2152 track.title || "Untitled Track" 2153 ] }), 2154 track.status && track.status !== "completed" && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "px-1.5 py-0.5 bg-amber-500/10 dark:bg-amber-500/20 border border-amber-500/30 dark:border-amber-500/40 text-amber-600 dark:text-amber-400 text-[8px] font-black uppercase rounded tracking-tight", children: track.status }) 2155 ] }),
2156 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [ 2157 track.sizeBytes !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] px-1.5 py-0.5 bg-zinc-100 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded text-zinc-500 dark:text-zinc-400 font-bold", children: formatBytes(track.sizeBytes) }), 2158 track.createdAt && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-400 font-medium", children: new Date(track.createdAt).toLocaleDateString() }) 2159 ] }) 2160 ] }), 2161 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1 mt-1.5", children: track.missing.map((key) => { 2162 const labels = { 2163 sourceMidi: "Orig MIDI", 2164 cleanMidi: "Clean MIDI", 2165 audio: "Audio MP3", 2166 highOpus: "Opus High", 2167 waveformJson: "Waveform", 2168 pianoRoll: "Piano Roll", 2169 thumbnail: "WebP Thumb", 2170 instruments: "DB Stems Info", 2171 midiMetadata: "DB Metadata", 2172 cleanedFileHash: "DB File Hash", 2173 dbThumbnail: "DB Thumb Path", 2174 difficulty: "DB Difficulty", 2175 duration: "DB Duration" 2176 }; 2177 return /* @__PURE__ */ jsxRuntimeExports.jsxs( 2178 "span", 2179 { 2180 className: "text-[9px] font-black uppercase tracking-tight px-1.5 py-0.5 bg-red-50 dark:bg-red-950/20 text-red-650 border border-red-100 dark:border-red-950/40 rounded", 2181 children: [ 2182 "Missing: ", 2183 labels[key] || key 2184 ] 2185 }, 2186 key 2187 ); 2188 }) }) 2189 ] }) 2190 ] 2191 }, 2192 track.id 2193 ); 2194 }) }),
2195 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-indigo-50/20 dark:bg-indigo-950/10 border border-indigo-100 dark:border-indigo-950/20 rounded-xl flex flex-col md:flex-row items-center justify-between gap-4", children: [ 2196 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs font-bold text-zinc-700 dark:text-zinc-300 shrink-0", children: [ 2197 selectedUnhealthyIds.length, 2198 " track(s) selected for asset regeneration." 2199 ] }), 2200 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row gap-2 w-full md:w-auto", children: [ 2201 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2202 "button", 2203 { 2204 onClick: () => handleReprocessSelected(true), 2205 disabled: isReprocessing || selectedUnhealthyIds.length === 0, 2206 className: "px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl text-xs font-bold flex items-center justify-center gap-2 transition-all disabled:opacity-50 shadow-sm shadow-indigo-600/10", 2207 children: [
2208 isReprocessing ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { size: 14 }), 2209 isReprocessing ? "Submitting..." : "Regenerate Missing Files Only" 2210 ] 2211 } 2212 ), 2213 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2214 "button", 2215 { 2216 onClick: () => handleReprocessSelected(false), 2217 disabled: isReprocessing || selectedUnhealthyIds.length === 0, 2218 className: "px-4 py-2 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-800 text-zinc-700 dark:text-zinc-300 rounded-xl text-xs font-bold flex items-center justify-center gap-2 transition-all disabled:opacity-50", 2219 children: [ 2220 isReprocessing ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 14 }), 2221 isReprocessing ? "Submitting..." : "Full Reprocess (All Steps)" 2222 ] 2223 } 2224 ) 2225 ] }) 2226 ] }) 2227 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-emerald-100 dark:border-emerald-950/30 bg-emerald-50/20 dark:bg-emerald-950/10 rounded-xl p-6 flex flex-col items-center justify-center py-8", children: [
2228 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { className: "text-emerald-500 mb-2 animate-bounce", size: 32 }), 2229 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-emerald-800 dark:text-emerald-400", children: "All Systems Nominal!" }), 2230 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-emerald-600 dark:text-emerald-500 mt-1", children: "100% of scanned tracks contain all mandatory media and data assets on disk." }) 2231 ] }) 2232 ) : ( 2233 /* Visual Asset Map */ 2234 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6 animate-in fade-in duration-200", children: [ 2235 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row sm:items-center justify-between gap-4 bg-zinc-50 dark:bg-zinc-800/10 p-3 rounded-xl border border-zinc-200/50 dark:border-zinc-800/65", children: [ 2236 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
2237 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-black uppercase text-zinc-400 tracking-wider", children: "Display Mode:" }), 2238 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2239 "select", 2240 { 2241 value: mapSortMode, 2242 onChange: (e) => setMapSortMode(e.target.value), 2243 className: "px-2.5 py-1.5 bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg text-xs font-bold text-zinc-700 dark:text-zinc-300 focus:outline-none focus:ring-1 focus:ring-indigo-500 cursor-pointer", 2244 children: [ 2245 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "sequential", children: "Database Order (ID Sequential)" }), 2246 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "sorted", children: "Sorted & Grouped (Integrity Completeness)" }) 2247 ] 2248 } 2249 ) 2250 ] }),
2251 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center flex-wrap gap-x-4 gap-y-1.5 text-[9px] font-bold text-zinc-500", children: [ 2252 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 2253 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded bg-emerald-500 inline-block" }), 2254 "All Made (6/6)" 2255 ] }), 2256 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 2257 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded bg-slate-700 inline-block" }), 2258 "Partial (5/6)" 2259 ] }), 2260 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 2261 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded bg-slate-400 inline-block" }), 2262 "Partial (3/6)" 2263 ] }),
2264 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 2265 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded bg-slate-200 inline-block" }), 2266 "Partial (1/6)" 2267 ] }), 2268 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 2269 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded bg-red-500 inline-block" }), 2270 "Empty (0/6)" 2271 ] }), 2272 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "flex items-center gap-1", children: [ 2273 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2.5 h-2.5 rounded border border-amber-500 bg-zinc-900 inline-block animate-pulse" }), 2274 "Processing" 2275 ] }) 2276 ] }) 2277 ] }), 2278 mapTracks.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-8 text-center text-zinc-400 italic text-xs font-bold", children: "No map data loaded. Ensure ID range is specified and scan is executed." }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
2279 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1 p-4 bg-zinc-50 dark:bg-zinc-950/20 border border-zinc-200 dark:border-zinc-800/80 rounded-xl max-h-[450px] overflow-y-auto custom-scrollbar justify-start items-start", children: getSortedTracks(mapTracks).map((track) => { 2280 const isSelected = (selectedMapTrack == null ? void 0 : selectedMapTrack.id) === track.id; 2281 const isProcessing = track.status !== "completed" && track.status !== "pending" && track.status !== "rejected" && track.status !== "failed" && track.status !== "suspended" && track.status !== "paused"; 2282 const isPending = track.status === "pending"; 2283 let bgStyle = {}; 2284 let bgClass = ""; 2285 if (track.totalCreated === 6) { 2286 bgClass = "bg-emerald-500 hover:bg-emerald-600 dark:bg-emerald-600 dark:hover:bg-emerald-700"; 2287 } else if (track.totalCreated === 0) { 2288 bgClass = "bg-red-500 hover:bg-red-600 dark:bg-red-650 dark:hover:bg-red-750"; 2289 } else { 2290 bgStyle = { backgroundColor: `hsl(215, 20%, ${75 - (track.totalCreated - 1) * 12}%)` }; 2291 bgClass = "hover:brightness-90 dark:hover:brightness-110"; 2292 } 2293 return /* @__PURE__ */ jsxRuntimeExports.jsx( 2294 "div", 2295 { 2296 onClick: () => setSelectedMapTrack(track), 2297 style: bgStyle, 2298 className: `group relative w-6 h-6 rounded cursor-pointer transition-all hover:scale-115 flex items-center justify-center text-[8px] font-bold ${bgClass} ${isSelected ? "ring-2 ring-indigo-500 ring-offset-2 dark:ring-offset-zinc-900 scale-110 shadow-lg" : isProcessing ? "ring-2 ring-amber-500 animate-pulse" : isPending ? "ring-1 ring-amber-400 ring-dashed" : "border border-black/10 dark:border-white/5"}`, 2299 children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "absolute bottom-full mb-1.5 hidden group-hover:block bg-zinc-950 text-white text-[9px] font-bold p-1 px-2 rounded shadow-xl whitespace-nowrap z-50 pointer-events-none", children: [ 2300 "#", 2301 track.id, 2302 ": ", 2303 track.totalCreated, 2304 "/6 (", 2305 track.title || "Untitled", 2306 ")" 2307 ] }) 2308 }, 2309 track.id 2310 ); 2311 }) }), 2312 selectedMapTrack ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl flex flex-col md:flex-row gap-6 animate-in slide-in-from-bottom duration-250", children: [
2313 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 space-y-3", children: [ 2314 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2315 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [ 2316 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "px-2 py-0.5 bg-indigo-500/10 border border-indigo-500/20 text-indigo-600 dark:text-indigo-400 text-[10px] font-mono font-black rounded", children: [ 2317 "ID #", 2318 selectedMapTrack.id 2319 ] }), 2320 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-black text-zinc-850 dark:text-zinc-150", children: selectedMapTrack.title || "Untitled Track" }), 2321 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[8px] font-black uppercase tracking-wider px-1.5 py-0.5 rounded ${selectedMapTrack.status === "completed" ? "bg-emerald-500/10 text-emerald-600 border border-emerald-500/20" : selectedMapTrack.status === "rejected" || selectedMapTrack.status === "failed" ? "bg-red-500/10 text-red-650 border border-red-500/20" : "bg-amber-500/10 text-amber-600 border border-amber-500/20 animate-pulse"}`, children: selectedMapTrack.status || "unknown" }) 2322 ] }),
2323 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] text-zinc-400 mt-1 font-bold", children: [ 2324 "Integrity Score: ", 2325 selectedMapTrack.totalCreated, 2326 " / 6 assets generated (", 2327 Math.round(selectedMapTrack.totalCreated / 6 * 100), 2328 "%)" 2329 ] }) 2330 ] }), 2331 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-2 gap-2 text-[10px] font-bold", children: [ 2332 { key: "cleanMidi", label: "Cleaned MIDI File" }, 2333 { key: "studioXml", label: "MuseScore Score XML" }, 2334 { key: "audio", label: "Audio MP3 Render" }, 2335 { key: "waveformJson", label: "Waveform Structure" }, 2336 { key: "pianoRoll", label: "Piano Roll Data" }, 2337 { key: "thumbnail", label: "WebP Preview Thumb" } 2338 ].map((asset) => { 2339 const isPresent = !selectedMapTrack.missing.includes(asset.key); 2340 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 p-1.5 rounded-lg bg-white dark:bg-zinc-950/40 border border-zinc-100 dark:border-zinc-800/60", children: [ 2341 isPresent ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { className: "text-emerald-500 shrink-0", size: 13 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "text-red-500 shrink-0", size: 13 }),
2342 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: isPresent ? "text-zinc-700 dark:text-zinc-300" : "text-red-500 font-black", children: asset.label }) 2343 ] }, asset.key); 2344 }) }) 2345 ] }), 2346 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col justify-between items-stretch md:items-end gap-3 min-w-[160px] border-t md:border-t-0 md:border-l border-zinc-250/40 dark:border-zinc-800/60 pt-4 md:pt-0 md:pl-6", children: [ 2347 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[10px] text-zinc-400 font-bold md:text-right", children: [ 2348 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-zinc-500", children: "Asset Size Sum" }), 2349 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-sm font-black text-indigo-600 dark:text-indigo-400 mt-0.5", children: formatBytes(selectedMapTrack.sizeBytes) }) 2350 ] }),
2351 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2 w-full", children: [ 2352 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2353 "button", 2354 { 2355 onClick: () => handleSingleReprocess(selectedMapTrack.id, true), 2356 className: "w-full px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-[10px] font-black uppercase flex items-center justify-center gap-1.5 transition-all shadow-sm shadow-indigo-600/10", 2357 children: [ 2358 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheckBig, { size: 11 }), 2359 "Regen Missing Only" 2360 ] 2361 } 2362 ), 2363 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2364 "button", 2365 { 2366 onClick: () => handleSingleReprocess(selectedMapTrack.id, false), 2367 className: "w-full px-3 py-1.5 bg-white dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-900 text-zinc-650 dark:text-zinc-400 rounded-lg text-[10px] font-black uppercase flex items-center justify-center gap-1.5 transition-all", 2368 children: [
2369 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 11 }), 2370 "Full Reprocess" 2371 ] 2372 } 2373 ), 2374 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2375 "button", 2376 { 2377 onClick: () => handleTriggerReplaceForId(selectedMapTrack.id), 2378 className: "w-full px-3 py-1.5 bg-white dark:bg-zinc-950 border border-zinc-200 dark:border-zinc-800 hover:bg-zinc-50 dark:hover:bg-zinc-900 text-zinc-650 dark:text-zinc-400 rounded-lg text-[10px] font-black uppercase flex items-center justify-center gap-1.5 transition-all", 2379 children: [ 2380 /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 11 }), 2381 "Replace MIDI" 2382 ] 2383 } 2384 ), 2385 /* @__P
2385URE__ */ jsxRuntimeExports.jsxs( 2386 "a", 2387 { 2388 href: `/track/${selectedMapTrack.id}`, 2389 target: "_blank", 2390 rel: "noreferrer", 2391 className: "w-full px-3 py-1.5 bg-zinc-150 hover:bg-zinc-200 dark:bg-zinc-800 dark:hover:bg-zinc-700 text-zinc-700 dark:text-zinc-300 rounded-lg text-[10px] font-black uppercase flex items-center justify-center gap-1.5 transition-all text-center", 2392 children: [ 2393 /* @__PURE__ */ jsxRuntimeExports.jsx(Eye, { size: 11 }), 2394 "View Page" 2395 ] 2396 } 2397 ) 2398 ] }) 2399 ] }) 2400 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/10 border border-zinc-200/50 dark:border-zinc-800 rounded-xl text-center text-zinc-400 italic text-[11px] font-bold", children: "ð¡ Tip: Click any square cell in the visual map above to inspect file paths, check individual asset status, and run quick actions." }) 2401 ] }) 2402 ] }) 2403 ) 2404 ] }) 2405 ] }),
2406 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [ 2407 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-zinc-100 dark:border-zinc-800 pb-4 mb-4", children: [ 2408 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-black uppercase text-zinc-900 dark:text-white flex items-center gap-2", children: [ 2409 /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 20, className: "text-indigo-500" }), 2410 " Bulk Reprocess MIDI Range" 2411 ] }), 2412 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 mt-1", children: "Re-queue and re-generate media and analysis assets for a pre-defined range of MIDI IDs. You can perform a full processing run or target specific asset types only." }) 2413 ] }), 2414 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6", children: [
2415 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [ 2416 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-4", children: [ 2417 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2418 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Start ID" }), 2419 /* @__PURE__ */ jsxRuntimeExports.jsx( 2420 "input", 2421 { 2422 type: "number", 2423 placeholder: "e.g. 1", 2424 value: bulkStartId, 2425 onChange: (e) => setBulkStartId(e.target.value), 2426 className: `w-full px-3 py-2 text-xs bg-zinc-50 dark:bg-zinc-800 border rounded-lg text-zinc-800 dark:text-zinc-100 font-bold focus:outline-none focus:ring-1 focus:ring-indigo-500 transition-all duration-500 ${isConfigured ? "border-emerald-500 ring-2 ring-emerald-500/20 dark:ring-emerald-500/10 dark:border-emerald-500 bg-emerald-50/10 dark:bg-emerald-950/10" : "border-zinc-200 dark:border-zinc-700"}` 2427 } 2428 ) 2429 ] }),
2430 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2431 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] font-black uppercase text-zinc-400 mb-1", children: "End ID" }), 2432 /* @__PURE__ */ jsxRuntimeExports.jsx( 2433 "input", 2434 { 2435 type: "number", 2436 placeholder: "e.g. 100", 2437 value: bulkEndId, 2438 onChange: (e) => setBulkEndId(e.target.value), 2439 className: `w-full px-3 py-2 text-xs bg-zinc-50 dark:bg-zinc-800 border rounded-lg text-zinc-800 dark:text-zinc-100 font-bold focus:outline-none focus:ring-1 focus:ring-indigo-500 transition-all duration-500 ${isConfigured ? "border-emerald-500 ring-2 ring-emerald-500/20 dark:ring-emerald-500/10 dark:border-emerald-500 bg-emerald-50/10 dark:bg-emerald-950/10" : "border-zinc-200 dark:border-zinc-700"}` 2440 } 2441 ) 2442 ] }) 2443 ] }),
2444 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "p-3.5 bg-zinc-50 dark:bg-zinc-800/25 rounded-xl border border-zinc-200/50 dark:border-zinc-800", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [ 2445 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ 2446 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-black uppercase text-zinc-700 dark:text-zinc-300 tracking-wider", children: "Resume / Skip Strategy" }), 2447 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-bold text-indigo-600 dark:text-indigo-400 uppercase tracking-tight bg-indigo-50 dark:bg-indigo-950/45 px-2 py-0.5 rounded", children: "Smart Filter" }) 2448 ] }), 2449 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2450 "select", 2451 { 2452 value: bulkSkipCompleted, 2453 onChange: (e) => setBulkSkipCompleted(e.target.value), 2454 className: "w-full px-2.5 py-1.5 text-xs bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-700 rounded-lg text-zinc-800 dark:text-zinc-100 font-bold focus:outline-none focus:ring-1 focus:ring-indigo-500", 2455 children: [
2456 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "both", children: "Skip if BOTH Studio Engraved & Audio Synthesis exist [Safe Resume]" }), 2457 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "sheets", children: "Skip if ONLY Studio Engraved exists [Skip Studio Engraved]" }), 2458 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "playback", children: "Skip if ONLY Audio Synthesis exists [Skip Audio Synthesis]" }), 2459 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "strict", children: "Skip if Studio Engraved, Audio Synthesis AND Animated Thumbnail exist [Strict Check]" }), 2460 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "none", children: "Do Not Skip (Force Overwrite / Regenerate All in Range)" }) 2461 ] 2462 } 2463 ), 2464 /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[9px] font-bold text-zinc-400 dark:text-zinc-500 leading-normal", children: [ 2465 bulkSkipCompleted === "both" && "ð¡ Highly Recommended. Only processes tracks missing either their Studio Engraved score or synthesized audio.", 2466 bulkSkipCompleted === "sheets" && "ð¡ Bypasses any track that already has a MuseScore Studio Engraved score file (studioPath).", 2467 bulkSkipCompleted === "playback" && "ð¡ Bypasses any track that already has ready Synthesized playback audio (opusPath/audioPath).", 2468 bulkSkipCompleted === "strict" && "ð¡ Ensures maximum health. Regenerates tracks missing even their Animated WebP Preview Thumbnail.", 2469 bulkSkipCompleted === "none" && "â ï¸ Caution: Will completely overwrite existing assets. Safe but takes longer." 2470 ] }) 2471 ] }) }),
2472 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/20 border border-zinc-100 dark:border-zinc-800/60 rounded-xl", children: [ 2473 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between mb-3", children: [ 2474 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 2475 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-800 dark:text-zinc-200", children: "Asset Options" }), 2476 !bulkFullProcess && pipelineSteps.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 text-[9px] font-black uppercase text-indigo-600", children: [ 2477 /* @__PURE__ */ jsxRuntimeExports.jsx( 2478 "button", 2479 { 2480 type: "button", 2481 onClick: () => setBulkSteps(pipelineSteps.map((s) => s.slug)), 2482 className: "hover:underline", 2483 children: "Select All" 2484 } 2485 ),
2486 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-300 dark:text-zinc-700", children: "|" }), 2487 /* @__PURE__ */ jsxRuntimeExports.jsx( 2488 "button", 2489 { 2490 type: "button", 2491 onClick: () => setBulkSteps([]), 2492 className: "hover:underline", 2493 children: "Deselect All" 2494 } 2495 ) 2496 ] }) 2497 ] }), 2498 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-end", children: [ 2499 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer", children: [ 2500 /* @__PURE__ */ jsxRuntimeExports.jsx( 2501 "input", 2502 { 2503 type: "checkbox", 2504 checked: bulkFullProcess, 2505 onChange: (e) => setBulkFullProcess(e.target.checked), 2506 className: "rounded border-zinc-300 dark:border-zinc-700 text-indigo-600 focus:ring-indigo-500 h-4 w-4" 2507 } 2508 ),
2509 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-black uppercase text-indigo-600 dark:text-indigo-400", children: "Full Process" }) 2510 ] }), 2511 bulkFullProcess && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[8px] text-zinc-400 dark:text-zinc-500 mt-0.5 block font-bold text-right tracking-tight", children: [ 2512 "Using: ", 2513 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: ((_t = config == null ? void 0 : config.enabledSteps) == null ? void 0 : _t.length) <= 6 ? "text-amber-500 font-black" : "text-indigo-500 font-black", children: ((_u = config == null ? void 0 : config.enabledSteps) == null ? void 0 : _u.length) <= 6 ? "Express Ingestion Profile" : "Full Production Profile" }) 2514 ] }) 2515 ] }) 2516 ] }), 2517 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-2 gap-2 text-[11px] font-bold max-h-[180px] overflow-y-auto pr-1 scrollbar-thin", children: pipelineSteps.map((item) => /* @__PURE__ */ jsxRuntimeExports.jsxs( 2518 "label", 2519 { 2520 className: `flex items-center gap-2 p-2 rounded-lg border cursor-pointer transition-all ${bulkFullProcess ? "opacity-50 cursor-not-allowed border-zinc-100 dark:border-zinc-800 bg-zinc-100/40 dark:bg-zinc-800/10 text-zinc-450" : bulkSteps.includes(item.slug) ? "border-indigo-200 bg-indigo-50/10 text-indigo-600 dark:border-indigo-950 dark:bg-indigo-950/10 dark:text-indigo-400" : "border-zinc-150 dark:border-zinc-800 bg-white dark:bg-zinc-900 text-zinc-600 dark:text-zinc-400 hover:bg-zinc-50 dark:hover:bg-zinc-800"}`, 2521 children: [
2522 /* @__PURE__ */ jsxRuntimeExports.jsx( 2523 "input", 2524 { 2525 type: "checkbox", 2526 disabled: bulkFullProcess, 2527 checked: bulkFullProcess || bulkSteps.includes(item.slug), 2528 onChange: () => { 2529 setBulkSteps( 2530 (prev) => prev.includes(item.slug) ? prev.filter((s) => s !== item.slug) : [...prev, item.slug] 2531 ); 2532 }, 2533 className: "rounded border-zinc-300 dark:border-zinc-700 text-indigo-600 focus:ring-indigo-500 h-3.5 w-3.5" 2534 } 2535 ), 2536 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "truncate", title: item.name, children: item.name }) 2537 ] 2538 }, 2539 item.slug 2540 )) }) 2541 ] }) 2542 ] }), 2543 /* @__P
2543URE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col justify-between p-5 bg-zinc-50 dark:bg-zinc-800/10 border border-zinc-200/50 dark:border-zinc-800 rounded-xl", children: [ 2544 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2545 /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { className: "text-xs font-bold text-zinc-800 dark:text-zinc-200 mb-2", children: "Job Configuration Review" }), 2546 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-1.5 text-[11px] text-zinc-500 dark:text-zinc-400 font-bold", children: [ 2547 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between border-b border-zinc-100 dark:border-zinc-800 pb-1.5", children: [ 2548 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Start ID:" }), 2549 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-800 dark:text-zinc-200", children: bulkStartId || "â" }) 2550 ] }),
2551 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between border-b border-zinc-100 dark:border-zinc-800 pb-1.5", children: [ 2552 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "End ID:" }), 2553 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-800 dark:text-zinc-200", children: bulkEndId || "â" }) 2554 ] }), 2555 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between border-b border-zinc-100 dark:border-zinc-800 pb-1.5", children: [ 2556 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Est. Track Count:" }), 2557 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-indigo-600 dark:text-indigo-400", children: !isNaN(parseInt(bulkStartId)) && !isNaN(parseInt(bulkEndId)) ? Math.max(0, parseInt(bulkEndId) - parseInt(bulkStartId) + 1) : "â" }) 2558 ] }), 2559 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between border-b border-zinc-100 dark:border-zinc-800 pb-1.5", children: [
2560 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Skip Strategy:" }), 2561 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: bulkSkipCompleted !== "none" ? "text-emerald-600 dark:text-emerald-400 font-black text-right" : "text-amber-600 dark:text-amber-400 font-black text-right", children: [ 2562 bulkSkipCompleted === "both" && "SKIP IF STUDIO XML & AUDIO EXIST", 2563 bulkSkipCompleted === "sheets" && "SKIP IF STUDIO XML EXISTS", 2564 bulkSkipCompleted === "playback" && "SKIP IF AUDIO SYNTHESIS EXISTS", 2565 bulkSkipCompleted === "strict" && "STRICT CHECK (STUDIO, AUDIO & THUMBNAIL)", 2566 bulkSkipCompleted === "none" && "FORCE RE-PROCESS ALL" 2567 ] }) 2568 ] }), 2569 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between border-b border-zinc-100 dark:border-zinc-800 pb-1.5", children: [ 2570 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Target Run:" }),
2571 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-800 dark:text-zinc-200 font-black", children: bulkFullProcess ? "FULL RE-PROCESSING" : "SELECTIVE FILE RE-GENERATION" }) 2572 ] }), 2573 bulkFullProcess && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between", children: [ 2574 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Active Profile:" }), 2575 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: ((_v = config == null ? void 0 : config.enabledSteps) == null ? void 0 : _v.length) <= 6 ? "text-amber-500 font-black" : "text-indigo-500 font-black", children: ((_w = config == null ? void 0 : config.enabledSteps) == null ? void 0 : _w.length) <= 6 ? `EXPRESS INGESTION (${((_x = config == null ? void 0 : config.enabledSteps) == null ? void 0 : _x.length) || 0} steps)` : `FULL WORKFLOW (${((_y = config == null ? void 0 : config.enabledSteps) == null ? void 0 : _y.length) || 0} steps)` }) 2576 ] }) 2577 ] }) 2578 ] }),
2579 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs( 2580 "button", 2581 { 2582 onClick: handleBulkReprocessRange, 2583 disabled: isBulkProcessing || !bulkStartId || !bulkEndId, 2584 className: "w-full py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-xs font-bold shadow-sm flex items-center justify-center gap-2 transition-all disabled:opacity-50", 2585 children: [ 2586 isBulkProcessing ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 14 }), 2587 isBulkProcessing ? "Queuing Batch..." : "Queue Bulk Processing" 2588 ] 2589 } 2590 ) }) 2591 ] }) 2592 ] }) 2593 ] }), 2594 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [
2595 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-zinc-100 dark:border-zinc-800 pb-4 mb-4", children: [ 2596 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-black uppercase text-zinc-900 dark:text-white flex items-center gap-2", children: [ 2597 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { size: 20, className: "text-amber-500" }), 2598 " High Priority MIDI Processing" 2599 ] }), 2600 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 mt-1", children: "Instantly flag a specific MIDI ID to be processed by the very next available worker, bypassing the standard backlog queue and node affinity rules." }) 2601 ] }), 2602 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row items-stretch sm:items-center gap-4", children: [ 2603 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full sm:w-1/2", children: [ 2604 /* @__P
2604URE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Target MIDI ID" }), 2605 /* @__PURE__ */ jsxRuntimeExports.jsx( 2606 "input", 2607 { 2608 type: "number", 2609 placeholder: "Enter MIDI ID...", 2610 value: priorityMidiId, 2611 onChange: (e) => setPriorityMidiId(e.target.value), 2612 className: "w-full px-3 py-2 text-xs bg-zinc-50 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg text-zinc-800 dark:text-zinc-100 font-bold focus:outline-none focus:ring-1 focus:ring-amber-500" 2613 } 2614 ) 2615 ] }), 2616 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full sm:w-1/2 flex flex-col justify-end", children: [ 2617 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[10px] font-black uppercase text-transparent mb-1 hidden sm:block", children: "Â " }), 2618 /* @__P
2618URE__ */ jsxRuntimeExports.jsxs( 2619 "button", 2620 { 2621 onClick: handlePrioritizeMidi, 2622 disabled: isPrioritizing || !priorityMidiId, 2623 className: "w-full px-4 py-2 bg-amber-500 hover:bg-amber-600 text-white rounded-lg text-xs font-bold shadow-sm flex items-center justify-center gap-2 transition-all disabled:opacity-50", 2624 children: [ 2625 isPrioritizing ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { size: 14 }), 2626 isPrioritizing ? "Prioritizing..." : "Set as High Priority" 2627 ] 2628 } 2629 ) 2630 ] }) 2631 ] }) 2632 ] }), 2633 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { id: "replace-midi-card", className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [ 2634 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-zinc-100 dark:border-zinc-800 pb-4 mb-4", children: [
2635 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-black uppercase text-zinc-900 dark:text-white flex items-center gap-2", children: [ 2636 /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 20, className: "text-indigo-500" }), 2637 " Replace MIDI File by ID" 2638 ] }), 2639 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-zinc-500 dark:text-zinc-400 mt-1", children: "Instantly upload a new MIDI file to replace an existing track. This will delete all stale analyzed/generated assets and queue the track for a clean, full reprocessing run." }) 2640 ] }), 2641 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col sm:flex-row items-stretch sm:items-center gap-4", children: [ 2642 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full sm:w-1/3", children: [ 2643 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Target MIDI ID" }),
2644 /* @__PURE__ */ jsxRuntimeExports.jsx( 2645 "input", 2646 { 2647 type: "number", 2648 placeholder: "Enter MIDI ID...", 2649 value: replaceMidiId, 2650 onChange: (e) => setReplaceMidiId(e.target.value), 2651 className: "w-full px-3 py-2 text-xs bg-zinc-50 dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg text-zinc-800 dark:text-zinc-100 font-bold focus:outline-none focus:ring-1 focus:ring-indigo-500" 2652 } 2653 ) 2654 ] }), 2655 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full sm:w-2/3 flex flex-col justify-end", children: [ 2656 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-[10px] font-black uppercase text-zinc-400 mb-1", children: "Select New MIDI File" }), 2657 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [ 2658 /* @__PURE__ */ jsxRuntimeExports.jsx( 2659 "input", 2660 { 2661 type: "file", 2662 accept: ".mid,.midi", 2663 ref: midiFileInputRef, 2664 onChange: (e) => { 2665 var _a2; 2666 const file = (_a2 = e.target.files) == null ? void 0 : _a2[0]; 2667 setReplaceMidiFile(file || null); 2668 }, 2669 className: "hidden" 2670 } 2671 ),
2672 /* @__PURE__ */ jsxRuntimeExports.jsx( 2673 "button", 2674 { 2675 onClick: () => { 2676 var _a2; 2677 return (_a2 = midiFileInputRef.current) == null ? void 0 : _a2.click(); 2678 }, 2679 className: "flex-1 px-3 py-2 text-xs bg-zinc-50 dark:bg-zinc-800 hover:bg-zinc-100 dark:hover:bg-zinc-700 border border-zinc-200 dark:border-zinc-700 rounded-lg text-zinc-700 dark:text-zinc-300 font-medium transition-all text-left truncate", 2680 children: replaceMidiFile ? replaceMidiFile.name : "Choose MIDI file..." 2681 } 2682 ), 2683 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2684 "button", 2685 { 2686 onClick: async () => { 2687 const trackId = parseInt(replaceMidiId, 10); 2688 if (isNaN(trackId)) { 2689 alert("Please enter a valid numeric MIDI ID."); 2690 return; 2691 } 2692 if (!replaceMidiFile) { 2693 alert("Please select a MIDI file to upload."); 2694 return; 2695 } 2696 if (!confirm(`Are you sure you want to replace the MIDI file for track ID #${trackId}? This will delete all existing assets and queue the track for reprocessing.`)) { 2697 return; 2698 } 2699 setIsReplacingMidi(true); 2700 try { 2701 const res = await api.replaceMidi(trackId, replaceMidiFile); 2702 alert(res.message || "MIDI file replaced and queued successfully!"); 2703 setReplaceMidiId(""); 2704 setReplaceMidiFile(null); 2705 if (midiFileInputRef.current) midiFileInputRef.current.value = ""; 2706 initData(); 2707 } catch (err) { 2708 alert(`Replacement failed: ${err.message}`); 2709 } finally { 2710 setIsReplacingMidi(false); 2711 } 2712 }, 2713 disabled: isReplacingMidi || !replaceMidiId || !replaceMidiFile, 2714 className: "px-4 py-2 bg-indigo-600 hover:bg-indigo-700 text-white rounded-lg text-xs font-bold shadow-sm flex items-center justify-center gap-2 transition-all disabled:opacity-50 shrink-0", 2715 children: [ 2716 isReplacingMidi ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Upload, { size: 14 }), 2717 isReplacingMidi ? "Replacing..." : "Upload & Replace" 2718 ] 2719 } 2720 ) 2721 ] }) 2722 ] }) 2723 ] }) 2724 ] }),
2725 /* @__PURE__ */ jsxRuntimeExports.jsx( 2726 PipelineCapabilities, 2727 { 2728 steps: pipelineSteps, 2729 enabledSteps: config.enabledSteps || [], 2730 onToggle: toggleStep, 2731 onSelectAll: handleSelectAll, 2732 onSave: () => handleSaveConfig(), 2733 isSaving, 2734 error: pipelineError 2735 } 2736 ) 2737 ] }), 2738 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "lg:w-1/4 flex flex-col gap-6 shrink-0", children: [ 2739 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [ 2740 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-6", children: [ 2741 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-bold uppercase text-zinc-500 flex items-center gap-2 font-black", children: [ 2742 /* @__PURE__ */ jsxRuntimeExports.jsx(Cpu, { size: 16, className: "text-indigo-500" }), 2743 " Worker Nodes" 2744 ] }),
2745 /* @__PURE__ */ jsxRuntimeExports.jsx( 2746 "button", 2747 { 2748 onClick: fetchWorkerNodes, 2749 className: "p-1 bg-zinc-50 dark:bg-zinc-800 hover:bg-zinc-100 dark:hover:bg-zinc-700 border border-zinc-200 dark:border-zinc-700 text-zinc-650 dark:text-zinc-400 rounded transition-all", 2750 title: "Refresh Worker Nodes", 2751 children: /* @__PURE__ */ jsxRuntimeExports.jsx(RefreshCw, { size: 12, className: isLoadingNodes ? "animate-spin" : "" }) 2752 } 2753 ) 2754 ] }), 2755 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4", children: workerNodes.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 italic text-center py-4", children: "Loading worker nodes..." }) : workerNodes.map((node) => { 2756 var _a2, _b2, _c2, _d2, _e2; 2757 const heartbeat = node.heartbeat; 2758 const isOnline2 = node.isOnline || heartbeat && heartbeat.status === "online"; 2759 const isStarting = node.config.isStarting; 2760 const isPaused = !node.config.enabled; 2761 const cpu = (heartbeat == null ? void 0 : heartbeat.cpu) !== void 0 ? `${heartbeat.cpu}%` : "N/A"; 2762 const ram = (heartbeat == null ? void 0 : heartbeat.ram) !== void 0 ? `${heartbeat.ram}%` : "N/A"; 2763 const activeTasksCount = ((_a2 = heartbeat == null ? void 0 : heartbeat.active_tasks) == null ? void 0 : _a2.length) || 0; 2764 const tasksList = activeWorkerTasks[node.id] || []; 2765 const isAuditingQueue = isOnline2 && activeTasksCount === 0 && ((heartbeat == null ? void 0 : heartbeat.activity_state) === "auditing_queue" || (heartbeat == null ? void 0 : heartbeat.last_processed_at) && Date.now() - new Date(heartbeat.last_processed_at).getTime() < 18e4); 2766 let statusBadgeColor = "bg-zinc-400"; 2767 let statusTextColor = "text-zinc-500"; 2768 let statusText = "Offline"; 2769 if (isStarting) { 2770 statusBadgeColor = "bg-indigo-400"; 2771 statusTextColor = "text-indigo-450 dark:text-indigo-400"; 2772 statusText = "Starting"; 2773 } else if (isPaused) { 2774 statusBadgeColor = "bg-amber-500"; 2775 statusTextColor = "text-amber-500"; 2776 statusText = "Paused"; 2777 } else if (isOnline2) { 2778 const isIdleProbe = (heartbeat == null ? void 0 : heartbeat.is_idle_probe) || activeTasksCount === 0 && !isAuditingQueue; 2779 statusBadgeColor = isAuditingQueue ? "bg-amber-400" : isIdleProbe ? "bg-emerald-400/80" : "bg-emerald-500"; 2780 statusTextColor = isAuditingQueue ? "text-amber-500 dark:text-amber-400" : "text-emerald-500"; 2781 statusText = isAuditingQueue ? "Auditing Queue" : isIdleProbe ? "Online (Idle)" : "Online"; 2782 } 2783 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-50/50 dark:bg-zinc-800/20 border border-zinc-150 dark:border-zinc-800/60 rounded-xl flex flex-col gap-3", children: [
2784 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ 2785 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2786 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-800 dark:text-zinc-200", children: node.name }), 2787 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] text-zinc-400 font-mono ml-1.5", children: [ 2788 "(Node ", 2789 node.id, 2790 ")" 2791 ] }) 2792 ] }), 2793 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [ 2794 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `w-1.5 h-1.5 rounded-full ${statusBadgeColor} ${isOnline2 && !isPaused ? "animate-pulse" : ""}` }), 2795 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `text-[10px] font-black uppercase tracking-wide ${statusTextColor}`, children: [ 2796 statusText, 2797 " ", 2798 isOnline2 && !isPaused && (heartbeat == null ? void 0 : heartbeat.num_workers) !== void 0 ? `(${heartbeat.num_workers}/${node.config.scale || (node.id <= 2 ? 2 : 1)})` : "" 2799 ] }) 2800 ] }) 2801 ] }),
2802 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2 text-[10px] text-zinc-500 dark:text-zinc-400", children: [ 2803 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2804 "CPU: ", 2805 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "font-mono text-zinc-700 dark:text-zinc-300", children: cpu }) 2806 ] }), 2807 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2808 "RAM: ", 2809 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "font-mono text-zinc-700 dark:text-zinc-300", children: ram }) 2810 ] }) 2811 ] }), 2812 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2 text-[10px] text-zinc-500 dark:text-zinc-400 border-t border-zinc-200/50 dark:border-zinc-800/40 pt-2", children: [ 2813 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2814 "Host vCPU: ",
2815 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "font-mono text-zinc-750 dark:text-zinc-300", children: ((_b2 = node.specs) == null ? void 0 : _b2.total_cpu) || (heartbeat == null ? void 0 : heartbeat.total_cpu) ? `${((_c2 = node.specs) == null ? void 0 : _c2.total_cpu) || (heartbeat == null ? void 0 : heartbeat.total_cpu)} Cores` : "Unknown" }) 2816 ] }), 2817 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 2818 "Host RAM: ", 2819 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "font-mono text-zinc-750 dark:text-zinc-300", children: ((_d2 = node.specs) == null ? void 0 : _d2.total_ram) || (heartbeat == null ? void 0 : heartbeat.total_ram) ? formatRam(((_e2 = node.specs) == null ? void 0 : _e2.total_ram) || (heartbeat == null ? void 0 : heartbeat.total_ram)) : "Unknown" }) 2820 ] }) 2821 ] }), 2822 heartbeat && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[9px] text-zinc-400 dark:text-zinc-500 font-mono", children: [ 2823 "Last active: ", 2824 new Date(heartbeat.timestamp).toLocaleString() 2825 ] }),
2826 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center border-t border-zinc-200/50 dark:border-zinc-850 pt-2.5", children: [ 2827 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-zinc-500 dark:text-zinc-400", children: [ 2828 "Active Tasks: ", 2829 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { className: "text-zinc-700 dark:text-zinc-350", children: activeTasksCount }), 2830 isAuditingQueue && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-1.5 text-amber-500 dark:text-amber-400 font-bold", children: "(Auditing Queue)" }) 2831 ] }), 2832 activeTasksCount > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx( 2833 "button", 2834 { 2835 onClick: () => fetchWorkerTasks(node.id), 2836 className: "text-[9px] bg-zinc-100 hover:bg-zinc-200 dark:bg-zinc-800 dark:hover:bg-zinc-700 border border-zinc-200 dark:border-zinc-700 px-2 py-0.5 rounded font-bold transition-all text-zinc-700 dark:text-zinc-300", 2837 children: "View Tasks" 2838 } 2839 ) 2840 ] }), 2841 tasksList.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-zinc-100 dark:bg-zinc-950 border border-zinc-250 dark:border-zinc-850 rounded p-2 max-h-[80px] overflow-y-auto font-mono text-[9px] flex flex-col gap-1 custom-scrollbar", children: tasksList.map((t) => /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-between text-emerald-600 dark:text-emerald-400 shrink-0 truncate", title: t.title, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 2842 "#", 2843 t.id, 2844 ": ", 2845 t.title 2846 ] }) }, t.id)) }),
2847 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [ 2848 /* @__PURE__ */ jsxRuntimeExports.jsx( 2849 "button", 2850 { 2851 onClick: () => toggleWorkerEnabled(node.id, isOnline2 && !isPaused), 2852 disabled: isStarting, 2853 className: `flex-1 py-1 rounded text-[10px] font-bold flex items-center justify-center gap-1 border transition-all ${isStarting ? "bg-zinc-150 border-zinc-200 text-zinc-400 cursor-not-allowed" : isOnline2 && !isPaused ? "bg-zinc-100 hover:bg-zinc-200 dark:bg-zinc-800 dark:hover:bg-zinc-700 border-zinc-200 dark:border-zinc-700 text-zinc-700 dark:text-zinc-300" : "bg-indigo-50 hover:bg-indigo-100 dark:bg-indigo-950/20 dark:hover:bg-indigo-900/30 border-indigo-100 dark:border-indigo-900/50 text-indigo-700 dark:text-indigo-400"}`, 2854 children: isStarting ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 2855 /* @__P
2855URE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 10, className: "animate-spin" }), 2856 " Starting..." 2857 ] }) : isOnline2 && !isPaused ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 2858 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleStop, { size: 10 }), 2859 " Pause" 2860 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 2861 /* @__PURE__ */ jsxRuntimeExports.jsx(CirclePlay, { size: 10 }), 2862 " Start" 2863 ] }) 2864 } 2865 ), 2866 /* @__PURE__ */ jsxRuntimeExports.jsx( 2867 "button", 2868 { 2869 onClick: () => handleRestartWorker(node.id), 2870 disabled: restartingNodes[node.id], 2871 className: "flex-1 py-1 bg-red-50 hover:bg-red-100 dark:bg-red-950/20 dark:hover:bg-red-900/30 border border-red-200 dark:border-red-900/50 rounded text-[10px] font-bold flex items-center justify-center gap-1 transition-all text-red-700 dark:text-red-400 disabled:opacity-50 disabled:cursor-not-allowed", 2872 children: restartingNodes[node.id] ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2873 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 10, className: "animate-spin" }), 2874 " Restarting..." 2875 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 2876 /* @__PURE__ */ jsxRuntimeExports.jsx(RotateCw, { size: 10 }), 2877 " Restart" 2878 ] }) 2879 } 2880 ), 2881 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2882 "button", 2883 { 2884 onClick: () => setExpandedWorkerConfig((prev) => ({ ...prev, [node.id]: !prev[node.id] })), 2885 className: "flex-1 py-1 bg-zinc-100 hover:bg-zinc-200 dark:bg-zinc-800/40 dark:hover:bg-zinc-700/55 border border-zinc-200 dark:border-zinc-700 rounded text-[10px] font-bold flex items-center justify-center gap-1 transition-all text-zinc-700 dark:text-zinc-300", 2886 children: [ 2887 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings2, { size: 10 }), 2888 " Config" 2889 ] 2890 } 2891 ), 2892 !isOnline2 && /* @__PURE__ */ jsxRuntimeExports.jsx( 2893 "button", 2894 { 2895 onClick: () => handleDiagnoseWorker(node.id), 2896 disabled: diagnosingNodes[node.id], 2897 className: "flex-1 py-1 bg-amber-50 hover:bg-amber-100 dark:bg-amber-950/20 dark:hover:bg-amber-900/30 border border-amber-200 dark:border-amber-905/50 rounded text-[10px] font-bold flex items-center justify-center gap-1 transition-all text-amber-700 dark:text-amber-400 disabled:opacity-50 disabled:cursor-not-allowed", 2898 title: "Diagnose why this worker is offline", 2899 children: diagnosingNodes[node.id] ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
2900 /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 10, className: "animate-spin" }), 2901 " Diagnosing..." 2902 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 2903 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 10 }), 2904 " Diagnose" 2905 ] }) 2906 } 2907 ) 2908 ] }), 2909 diagnosticReports[node.id] && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-amber-50/70 dark:bg-amber-950/20 border border-amber-200/60 dark:border-amber-900/40 rounded-lg p-2.5 mt-1.5 text-[9px] text-amber-900 dark:text-amber-300 font-mono whitespace-pre-wrap relative animate-in fade-in slide-in-from-top-1", children: [ 2910 /* @__PURE__ */ jsxRuntimeExports.jsx( 2911 "button", 2912 { 2913 onClick: () => setDiagnosticReports((prev) => ({ ...prev, [node.id]: "" })), 2914 className: "absolute top-1.5 right-1.5 text-amber-500 hover:text-amber-700 dark:text-amber-400 dark:hover:text-amber-200 font-sans font-bold text-xs", 2915 title: "Clear report", 2916 children: "Ã" 2917 } 2918 ),
2919 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "font-bold border-b border-amber-200/50 dark:border-amber-900/30 pb-1 mb-1.5 flex items-center gap-1", children: [ 2920 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 10 }), 2921 " Diagnosis Report:" 2922 ] }), 2923 diagnosticReports[node.id] 2924 ] }), 2925 expandedWorkerConfig[node.id] && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-zinc-100/50 dark:bg-zinc-950/30 border border-zinc-200 dark:border-zinc-855 rounded p-2.5 flex flex-col gap-2.5 mt-1 animate-in fade-in slide-in-from-top-1", children: [ 2926 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[10px] text-zinc-500 dark:text-zinc-400", children: [ 2927 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Poll Interval (s)" }), 2928 /* @__PURE__ */ jsxRuntimeExports.jsx( 2929 "input", 2930 { 2931 type: "number", 2932 id: `worker-poll-${node.id}`, 2933 defaultValue: node.config.poll_interval, 2934 className: "w-14 font-mono text-[9px] bg-white dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 text-zinc-800 dark:text-zinc-100 py-0.5 px-1 text-center rounded outline-none" 2935 } 2936 ) 2937 ] }),
2938 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[10px] text-zinc-500 dark:text-zinc-400", children: [ 2939 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 2940 "Max Threads", 2941 node.id === 2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] text-emerald-500 ml-1 font-bold", children: "(Rec: 2)" }) 2942 ] }), 2943 /* @__PURE__ */ jsxRuntimeExports.jsx( 2944 "input", 2945 { 2946 type: "text", 2947 id: `worker-threads-${node.id}`, 2948 defaultValue: node.config.max_threads, 2949 placeholder: "auto", 2950 className: "w-14 font-mono text-[9px] bg-white dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 text-zinc-800 dark:text-zinc-100 py-0.5 px-1 text-center rounded outline-none" 2951 } 2952 ) 2953 ] }),
2954 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[10px] text-zinc-500 dark:text-zinc-400", children: [ 2955 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "CPU Limit (%)" }), 2956 /* @__PURE__ */ jsxRuntimeExports.jsx( 2957 "input", 2958 { 2959 type: "number", 2960 id: `worker-cpu-${node.id}`, 2961 defaultValue: node.config.cpu_threshold, 2962 className: "w-14 font-mono text-[9px] bg-white dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 text-zinc-800 dark:text-zinc-100 py-0.5 px-1 text-center rounded outline-none" 2963 } 2964 ) 2965 ] }), 2966 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[10px] text-zinc-500 dark:text-zinc-400", children: [ 2967 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Parallel Execution" }),
2968 /* @__PURE__ */ jsxRuntimeExports.jsx( 2969 "input", 2970 { 2971 type: "checkbox", 2972 id: `worker-parallel-${node.id}`, 2973 defaultChecked: node.config.parallelExecution || false, 2974 className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500 w-3.5 h-3.5" 2975 } 2976 ) 2977 ] }), 2978 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[10px] text-zinc-500 dark:text-zinc-400", children: [ 2979 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 2980 "Tasks Per CPU Core", 2981 node.id === 2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] text-emerald-500 ml-1 font-bold", children: "(Rec: 1x)" }) 2982 ] }), 2983 /* @__PURE__ */ jsxRuntimeExports.jsxs( 2984 "select", 2985 { 2986 id: `worker-tasks-per-cpu-${node.id}`, 2987 defaultValue: node.config.tasks_per_cpu || 1, 2988 className: "w-14 font-mono text-[9px] bg-white dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 text-zinc-800 dark:text-zinc-100 py-0.5 px-1 rounded outline-none", 2989 children: [
2990 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 1, children: "1x" }), 2991 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 2, children: "2x" }), 2992 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 3, children: "3x" }), 2993 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 4, children: "4x" }), 2994 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 5, children: "5x" }), 2995 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 6, children: "6x" }), 2996 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 8, children: "8x" }), 2997 /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: 10, children: "10x" }) 2998 ] 2999 } 3000 ) 3001 ] }), 3002 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center text-[10px] text-zinc-500 dark:text-zinc-400", children: [
3003 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 3004 "Scale (Workers)", 3005 node.id === 2 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] text-emerald-500 ml-1 font-bold", children: "(Rec: 25)" }) 3006 ] }), 3007 /* @__PURE__ */ jsxRuntimeExports.jsx( 3008 "input", 3009 { 3010 type: "number", 3011 id: `worker-scale-${node.id}`, 3012 defaultValue: node.config.scale || (node.id <= 2 ? 2 : 1), 3013 min: "1", 3014 max: "50", 3015 className: "w-14 font-mono text-[9px] bg-white dark:bg-zinc-900 border border-zinc-300 dark:border-zinc-700 text-zinc-800 dark:text-zinc-100 py-0.5 px-1 text-center rounded outline-none" 3016 } 3017 ) 3018 ] }), 3019 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
3020 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3021 "button", 3022 { 3023 type: "button", 3024 onClick: () => handleAutoTune(node), 3025 className: "flex-1 py-1 bg-amber-500 hover:bg-amber-600 dark:bg-amber-600 dark:hover:bg-amber-700 text-white rounded text-[10px] font-bold flex items-center justify-center gap-1 transition-colors shadow-sm animate-in fade-in zoom-in-95", 3026 title: "Auto-adjust config parameters based on available host resources", 3027 children: [ 3028 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { size: 10, className: "mr-1 text-amber-100" }), 3029 " Auto" 3030 ] 3031 } 3032 ), 3033 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3034 "button", 3035 { 3036 onClick: () => { 3037 var _a3, _b3, _c3, _d3, _e3, _f2, _g2; 3038 const poll = parseInt((_a3 = document.getElementById(`worker-poll-${node.id}`)) == null ? void 0 : _a3.value) || 5; 3039 const threadsVal = (_c3 = (_b3 = document.getElementById(`worker-threads-${node.id}`)) == null ? void 0 : _b3.value) == null ? void 0 : _c3.trim().toLowerCase(); 3040 const threads = threadsVal === "auto" || threadsVal === "" ? "auto" : parseInt(threadsVal) || 8; 3041 const cpu2 = parseInt((_d3 = document.getElementById(`worker-cpu-${node.id}`)) == null ? void 0 : _d3.value) || 80; 3042 const scale = parseInt((_e3 = document.getElementById(`worker-scale-${node.id}`)) == null ? void 0 : _e3.value) || (node.id <= 2 ? 2 : 1); 3043 const tasksPerCpu = parseInt((_f2 = document.getElementById(`worker-tasks-per-cpu-${node.id}`)) == null ? void 0 : _f2.value) || 1; 3044 const parallel = ((_g2 = document.getElementById(`worker-parallel-${node.id}`)) == null ? void 0 : _g2.checked) || false; 3045 saveWorkerConfig(node.id, poll, threads, cpu2, scale, tasksPerCpu, parallel); 3046 }, 3047 className: "flex-1 py-1 bg-indigo-650 hover:bg-indigo-700 text-white rounded text-[10px] font-bold flex items-center justify-center gap-1.5 transition-colors shadow-sm", 3048 children: [
3049 /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 10 }), 3050 " Save Config" 3051 ] 3052 } 3053 ) 3054 ] }) 3055 ] }) 3056 ] }, node.id); 3057 }) }) 3058 ] }), 3059 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [ 3060 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-6", children: [ 3061 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-bold uppercase text-zinc-500 flex items-center gap-2 font-bold uppercase", children: [ 3062 /* @__PURE__ */ jsxRuntimeExports.jsx(Activity, { size: 16, className: "text-indigo-500 animate-pulse" }), 3063 " Worker Instances" 3064 ] }), 3065 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] bg-indigo-100 dark:bg-indigo-950 font-extrabold px-2.5 py-1 rounded-md text-indigo-700 dark:text-indigo-300 border border-indigo-200 dark:border-indigo-900/50 shadow-sm shrink-0", children: [ 3066 instances.length, 3067 " Active" 3068 ] }) 3069 ] }),
3070 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2 mb-4 max-h-[160px] overflow-y-auto pr-1", children: !Array.isArray(instances) || instances.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-zinc-400 italic text-center py-4", children: "No active OS instances detected." }) : instances.map((inst) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center p-2.5 bg-zinc-50 dark:bg-zinc-800/30 border border-zinc-100 dark:border-zinc-800 rounded-xl hover:border-zinc-200 dark:hover:border-zinc-700 transition-all group", children: [ 3071 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col", children: [ 3072 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-xs font-bold text-zinc-900 dark:text-white flex items-center gap-1.5", children: [ 3073 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" }), 3074 "PID ", 3075 inst.pid 3076 ] }),
3077 inst.elapsed && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] text-zinc-400 font-mono mt-0.5", children: [ 3078 "Uptime: ", 3079 inst.elapsed 3080 ] }) 3081 ] }), 3082 /* @__PURE__ */ jsxRuntimeExports.jsx( 3083 "button", 3084 { 3085 onClick: () => handleTerminateInstance(inst.pid), 3086 className: "p-1.5 bg-amber-50 dark:bg-amber-950/20 text-amber-600 hover:bg-amber-100 dark:hover:bg-amber-900/40 rounded-lg transition-colors opacity-0 group-hover:opacity-100 focus:opacity-100", 3087 title: typeof inst.pid === "string" && (inst.pid.startsWith("win108_") || inst.pid.startsWith("gcp3_") || inst.pid.startsWith("gcp4_")) ? "Restart Remote Container" : "Gracefully Stop Instance", 3088 children: /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { size: 13 }) 3089 } 3090 ) 3091 ] }, inst.pid)) }), 3092 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mb-6 bg-zinc-50 dark:bg-zinc-800/20 p-3 rounded-xl border border-zinc-100 dark:border-zinc-800/50", children: [
3093 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between text-[10px] font-bold text-zinc-400 uppercase mb-1.5", children: [ 3094 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Worker Allocation" }), 3095 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 3096 instances.length, 3097 " / 30 Limit" 3098 ] }) 3099 ] }), 3100 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "w-full bg-zinc-200 dark:bg-zinc-800 h-2 rounded-full overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx( 3101 "div", 3102 { 3103 className: "bg-indigo-600 h-full rounded-full transition-all duration-500", 3104 style: { width: `${Math.min(100, instances.length / 30 * 100)}%` } 3105 } 3106 ) }) 3107 ] }), 3108 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4 border-t border-zinc-100 dark:border-zinc-800 pt-4", children: [
3109 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center", children: [ 3110 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-black uppercase text-zinc-400", children: "Target Scale" }), 3111 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5 bg-zinc-50 dark:bg-zinc-800/40 border border-zinc-100 dark:border-zinc-800 rounded-lg px-2 py-0.5", children: [ 3112 /* @__PURE__ */ jsxRuntimeExports.jsx( 3113 "button", 3114 { 3115 onClick: () => setTargetScale((prev) => Math.max(1, prev - 1)), 3116 className: "text-zinc-500 hover:text-indigo-600 p-0.5 rounded transition-colors", 3117 children: /* @__PURE__ */ jsxRuntimeExports.jsx(Minus, { size: 11 }) 3118 } 3119 ), 3120 /* @__PURE__ */ jsxRuntimeExports.jsx( 3121 "input", 3122 { 3123 type: "number", 3124 min: "1", 3125 max: "30", 3126 value: targetScale, 3127 onChange: (e) => { 3128 const val = parseInt(e.target.value); 3129 if (!isNaN(val)) { 3130 setTargetScale(Math.max(1, Math.min(30, val))); 3131 } 3132 }, 3133 className: "w-8 text-center text-xs font-black bg-transparent border-none focus:outline-none p-0 text-zinc-800 dark:text-zinc-100 [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none font-mono" 3134 } 3135 ),
3136 /* @__PURE__ */ jsxRuntimeExports.jsx( 3137 "button", 3138 { 3139 onClick: () => setTargetScale((prev) => Math.min(30, prev + 1)), 3140 className: "text-zinc-500 hover:text-indigo-600 p-0.5 rounded transition-colors", 3141 children: /* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { size: 11 }) 3142 } 3143 ) 3144 ] }) 3145 ] }), 3146 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 3147 /* @__PURE__ */ jsxRuntimeExports.jsx( 3148 "input", 3149 { 3150 type: "range", 3151 min: "1", 3152 max: "30", 3153 value: targetScale, 3154 onChange: (e) => setTargetScale(parseInt(e.target.value)), 3155 className: "flex-1 accent-indigo-600" 3156 } 3157 ), 3158 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-black text-zinc-900 dark:text-white w-6 text-right text-xs", children: targetScale }) 3159 ] }),
3160 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-6 gap-1", children: [1, 2, 4, 8, 16, 30].map((num) => { 3161 const isActive = targetScale === num; 3162 return /* @__PURE__ */ jsxRuntimeExports.jsx( 3163 "button", 3164 { 3165 onClick: () => setTargetScale(num), 3166 className: `py-1 text-[9px] font-black text-center border rounded-md transition-all ${isActive ? "border-indigo-600 bg-indigo-50/50 dark:bg-indigo-950/40 text-indigo-600 dark:text-indigo-400" : "border-zinc-100 dark:border-zinc-800 hover:border-indigo-200 hover:bg-indigo-50/10 text-zinc-500 hover:text-indigo-600"}`, 3167 title: `Set target scale to ${num}`, 3168 children: num 3169 }, 3170 num 3171 ); 3172 }) }), 3173 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "bg-zinc-50 dark:bg-zinc-800/10 p-2.5 rounded-xl border border-zinc-100 dark:border-zinc-800/40 text-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[9px] leading-relaxed font-bold text-zinc-500 dark:text-zinc-400", children: targetScale === instances.length ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-zinc-400 italic", children: "Current active worker scale matches target scale." }) : targetScale > instances.length ? /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-indigo-600 dark:text-indigo-400 flex items-center justify-center gap-1", children: [
3174 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { size: 10, className: "animate-pulse" }), 3175 " Spawn +", 3176 targetScale - instances.length, 3177 " worker(s) gracefully." 3178 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-amber-600 dark:text-amber-400 flex items-center justify-center gap-1", children: [ 3179 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { size: 10, className: "animate-pulse" }), 3180 " Scale down by -", 3181 instances.length - targetScale, 3182 " gracefully (active jobs will finish)." 3183 ] }) }) }), 3184 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3185 "button", 3186 { 3187 onClick: () => handleScaleCluster(targetScale), 3188 disabled: isScalingCluster || targetScale === instances.length, 3189 className: `w-full py-2.5 text-white rounded-xl text-xs font-black transition-all flex items-center justify-center gap-2 shadow-sm ${targetScale === instances.length ? "bg-zinc-100 dark:bg-zinc-800/50 text-zinc-400 dark:text-zinc-600 cursor-not-allowed shadow-none border border-zinc-200 dark:border-zinc-800/50" : targetScale > instances.length ? "bg-indigo-600 hover:bg-indigo-700 shadow-indigo-600/10 hover:shadow-indigo-600/20" : "bg-amber-600 hover:bg-amber-700 shadow-amber-600/10 hover:shadow-amber-600/20"}`, 3190 children: [ 3191 isScalingCluster ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : targetScale > instances.length ? /* @__PURE__ */ jsxRuntimeExports.jsx(CirclePlay, { size: 14 }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { size: 14 }), 3192 isScalingCluster ? `Scaling cluster to ${targetScale}...` : targetScale === instances.length ? "Cluster At Target Scale" : targetScale > instances.length ? `Scale Up Cluster (+${targetScale - instances.length})` : `Scale Down Gracefully (-${instances.length - targetScale})` 3193 ] 3194 } 3195 ),
3196 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-zinc-100 dark:border-zinc-800 pt-4 mt-2", children: [ 3197 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3198 "button", 3199 { 3200 onClick: handleCloseIdleInstances, 3201 disabled: isClosingIdle || instances.length <= 1, 3202 className: "w-full py-2 bg-zinc-50 dark:bg-zinc-800/40 hover:bg-zinc-100 dark:hover:bg-zinc-800 border border-zinc-100 dark:border-zinc-800 text-zinc-700 dark:text-zinc-300 rounded-xl text-xs font-bold transition-all flex items-center justify-center gap-2 disabled:opacity-40", 3203 children: [ 3204 isClosingIdle ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { size: 14, className: "text-red-500" }), 3205 isClosingIdle ? "Closing Idles..." : "Close All Idle Workers" 3206 ] 3207 } 3208 ),
3209 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[9px] text-zinc-400 dark:text-zinc-500 mt-2 text-center leading-relaxed", children: "Reclaims idle containers and local OS processes. Keeps active workers and maintains a minimum of 1 instance." }) 3210 ] }) 3211 ] }) 3212 ] }), 3213 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [ 3214 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-6", children: [ 3215 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-bold uppercase text-zinc-500 flex items-center gap-2", children: [ 3216 /* @__PURE__ */ jsxRuntimeExports.jsx(TrendingUp, { size: 16, className: "text-indigo-500" }), 3217 " Throughput Rates" 3218 ] }), 3219 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] bg-emerald-50 dark:bg-emerald-950 text-emerald-600 dark:text-emerald-400 font-extrabold px-2 py-0.5 rounded border border-emerald-100 dark:border-emerald-950/40 uppercase tracking-tight", children: "Live Metrics" }) 3220 ] }), 3221 throughputStats ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-4", children: [ 3222 { key: "m10", label: "Last 10 Mins", bucket: throughputStats.m10, color: "indigo" }, 3223 { key: "m30", label: "Last 30 Mins", bucket: throughputStats.m30, color: "indigo" }, 3224 { key: "m60", label: "Last 60 Mins", bucket: throughputStats.m60, color: "pink" }, 3225 { key: "h24", label: "Last 24 Hours", bucket: throughputStats.h24, color: "emerald" } 3226 ].map(({ label, bucket, color }) => { 3227 const hasData = bucket && bucket.count > 0; 3228 const hasConfig = hasData && bucket && bucket.config && (bucket.config.threads !== null || bucket.config.cpuSafety !== null || bucket.config.instances > 0); 3229 return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 bg-zinc-50 dark:bg-zinc-800/20 border border-zinc-100 dark:border-zinc-800/40 rounded-xl transition-all hover:border-zinc-200/60 dark:hover:border-zinc-700/40", children: [
3230 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-start mb-2", children: [ 3231 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-black text-zinc-400 uppercase tracking-wider", children: label }), 3232 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-right", children: [ 3233 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-sm font-black text-zinc-800 dark:text-zinc-200", children: [ 3234 bucket ? bucket.perHour : 0, 3235 " ", 3236 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-zinc-400 font-bold uppercase", children: "/hr" }) 3237 ] }), 3238 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-[9px] text-zinc-400 font-mono mt-0.5", children: [ 3239 bucket ? bucket.count : 0, 3240 " track(s) processed" 3241 ] }) 3242 ] }) 3243 ] }),
3244 hasData && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-[9px] text-zinc-500 font-bold mb-2", children: [ 3245 /* @__PURE__ */ jsxRuntimeExports.jsx(Clock, { size: 11, className: "text-zinc-400" }), 3246 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Avg processing:" }), 3247 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-zinc-700 dark:text-zinc-300", children: [ 3248 bucket.avgDurationSec, 3249 "s" 3250 ] }) 3251 ] }), 3252 hasData && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2 mb-2 pb-2 border-b border-dashed border-zinc-150 dark:border-zinc-800/60 text-[9px] font-bold", children: [ 3253 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-amber-600 dark:text-amber-400", children: [ 3254 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { size: 11, className: "text-amber-500 animate-pulse" }),
3255 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 3256 "Peak: ", 3257 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-zinc-700 dark:text-zinc-300", children: bucket.historicPeak !== void 0 ? `${bucket.historicPeak}/hr` : "â" }) 3258 ] }) 3259 ] }), 3260 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 text-indigo-600 dark:text-indigo-400", children: [ 3261 /* @__PURE__ */ jsxRuntimeExports.jsx(TrendingUp, { size: 11, className: "text-indigo-500" }), 3262 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [ 3263 "Avg: ", 3264 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-zinc-700 dark:text-zinc-300", children: bucket.historicAverage !== void 0 ? `${bucket.historicAverage}/hr` : "â" }) 3265 ] }) 3266 ] }) 3267 ] }), 3268 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-wrap gap-1 border-t border-dashed border-zinc-150 dark:border-zinc-800/60 pt-2", children: hasConfig ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [ 3269 bucket.config.instances > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] font-mono font-bold px-1.5 py-0.5 bg-indigo-50 dark:bg-indigo-950/40 text-indigo-600 dark:text-indigo-400 rounded-md border border-indigo-100 dark:border-indigo-900/20", children: [ 3270 bucket.config.instances, 3271 " Inst" 3272 ] }), 3273 bucket.config.threads !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] font-mono font-bold px-1.5 py-0.5 bg-purple-50 dark:bg-purple-950/40 text-purple-600 dark:text-purple-400 rounded-md border border-purple-100 dark:border-purple-900/20", children: [ 3274 bucket.config.threads, 3275 " Thrs" 3276 ] }), 3277 bucket.config.cpuSafety !== null && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] font-mono font-bold px-1.5 py-0.5 bg-amber-50 dark:bg-amber-950/40 text-amber-600 dark:text-amber-400 rounded-md border border-amber-100 dark:border-amber-900/20", children: [ 3278 bucket.config.cpuSafety, 3279 "% CPU Safety" 3280 ] }) 3281 ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-bold text-zinc-400 italic", children: "No recipe signature recorded" }) }) 3282 ] }, label); 3283 }) }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "py-6 flex flex-col items-center justify-center text-center", children: [
3284 /* @__PURE__ */ jsxRuntimeExports.jsx(Zap, { className: "text-zinc-300 animate-pulse mb-2", size: 24 }), 3285 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-400", children: "Waiting for completed jobs..." }) 3286 ] }) 3287 ] }), 3288 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "bg-white dark:bg-zinc-900 border border-zinc-200 dark:border-zinc-800 rounded-xl p-6 shadow-sm", children: [ 3289 /* @__PURE__ */ jsxRuntimeExports.jsxs("h3", { className: "text-sm font-bold uppercase text-zinc-500 mb-6 flex items-center gap-2 font-bold uppercase", children: [ 3290 /* @__PURE__ */ jsxRuntimeExports.jsx(Settings2, { size: 16, className: "text-zinc-500" }), 3291 " Runtime Settings" 3292 ] }), 3293 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-6", children: [ 3294 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 3295 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [
3296 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] font-bold text-zinc-500 dark:text-zinc-400 uppercase", children: "Polling Interval" }), 3297 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer text-[10px] font-bold text-zinc-500 hover:text-indigo-600 transition-colors", children: [ 3298 /* @__PURE__ */ jsxRuntimeExports.jsx( 3299 "input", 3300 { 3301 type: "checkbox", 3302 checked: config.poll_interval === "auto", 3303 onChange: (e) => { 3304 const val = e.target.checked ? "auto" : 5; 3305 const next = { ...config, poll_interval: val }; 3306 setConfig(next); 3307 handleSaveConfig(next); 3308 }, 3309 className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500 w-3.5 h-3.5" 3310 } 3311 ), 3312 "Auto" 3313 ] }) 3314 ] }),
3315 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 3316 /* @__PURE__ */ jsxRuntimeExports.jsx( 3317 "input", 3318 { 3319 type: "range", 3320 min: "1", 3321 max: "60", 3322 disabled: config.poll_interval === "auto", 3323 value: config.poll_interval === "auto" ? 5 : config.poll_interval || 5, 3324 onChange: (e) => setConfig({ ...config, poll_interval: parseInt(e.target.value) }), 3325 className: "flex-1 accent-indigo-600 disabled:opacity-40" 3326 } 3327 ), 3328 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-bold text-zinc-900 dark:text-white w-12 text-center text-xs", children: config.poll_interval === "auto" ? "Auto" : `${config.poll_interval}s` }) 3329 ] }) 3330 ] }), 3331 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
3332 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [ 3333 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] font-bold text-zinc-500 dark:text-zinc-400 uppercase", children: "Concurrency Limit (Max Threads)" }), 3334 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer text-[10px] font-bold text-zinc-500 hover:text-indigo-600 transition-colors", children: [ 3335 /* @__PURE__ */ jsxRuntimeExports.jsx( 3336 "input", 3337 { 3338 type: "checkbox", 3339 checked: config.max_threads === "auto", 3340 onChange: (e) => { 3341 const val = e.target.checked ? "auto" : 8; 3342 const next = { ...config, max_threads: val }; 3343 setConfig(next); 3344 handleSaveConfig(next); 3345 }, 3346 className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500 w-3.5 h-3.5" 3347 } 3348 ), 3349 "Auto" 3350 ] }) 3351 ] }),
3352 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 3353 /* @__PURE__ */ jsxRuntimeExports.jsx( 3354 "input", 3355 { 3356 type: "range", 3357 min: "1", 3358 max: "64", 3359 disabled: config.max_threads === "auto", 3360 value: config.max_threads === "auto" ? 8 : config.max_threads || 8, 3361 onChange: (e) => setConfig({ ...config, max_threads: parseInt(e.target.value) }), 3362 className: "flex-1 accent-indigo-600 disabled:opacity-40" 3363 } 3364 ), 3365 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-bold text-zinc-900 dark:text-white w-12 text-center text-xs", children: config.max_threads === "auto" ? "Auto" : config.max_threads || 8 }) 3366 ] }), 3367 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[9px] text-zinc-400 dark:text-zinc-500 mt-1 leading-tight block", children: [ 3368 "Max tasks processed simultaneously ",
3369 /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "per active worker container/instance" }), 3370 ". (Global Limit = Max Threads à Container Scale)" 3371 ] }) 3372 ] }), 3373 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 3374 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-2", children: [ 3375 /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] font-bold text-zinc-500 dark:text-zinc-400 uppercase", children: "CPU Safety Threshold" }), 3376 /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-1.5 cursor-pointer text-[10px] font-bold text-zinc-500 hover:text-indigo-600 transition-colors", children: [ 3377 /* @__PURE__ */ jsxRuntimeExports.jsx( 3378 "input", 3379 { 3380 type: "checkbox", 3381 checked: config.cpu_threshold === "auto", 3382 onChange: (e) => { 3383 const val = e.target.checked ? "auto" : 80; 3384 const next = { ...config, cpu_threshold: val }; 3385 setConfig(next); 3386 handleSaveConfig(next); 3387 }, 3388 className: "rounded border-zinc-300 text-indigo-600 focus:ring-indigo-500 w-3.5 h-3.5" 3389 } 3390 ), 3391 "Auto" 3392 ] }) 3393 ] }),
3394 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4", children: [ 3395 /* @__PURE__ */ jsxRuntimeExports.jsx( 3396 "input", 3397 { 3398 type: "range", 3399 min: "10", 3400 max: "3200", 3401 step: "10", 3402 disabled: config.cpu_threshold === "auto", 3403 value: config.cpu_threshold === "auto" ? 80 : config.cpu_threshold || 80, 3404 onChange: (e) => setConfig({ ...config, cpu_threshold: parseInt(e.target.value) }), 3405 className: "flex-1 accent-indigo-600 disabled:opacity-40" 3406 } 3407 ), 3408 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono font-bold text-zinc-900 dark:text-white w-16 text-center text-xs", children: config.cpu_threshold === "auto" ? "Auto" : `${config.cpu_threshold || 80}%` }) 3409 ] }), 3410 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-400 dark:text-zinc-500 mt-1 leading-tight block", children: "Host CPU safety limit. A container will pause polling new tasks if its aggregate CPU usage exceeds this threshold." }) 3411 ] }),
3412 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 3413 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex justify-between items-center mb-2", children: /* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-[10px] font-bold text-zinc-500 dark:text-zinc-400 uppercase", children: "Parallel Execution" }) }), 3414 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "flex items-center gap-2 cursor-pointer", children: [ 3415 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "relative", children: [ 3416 /* @__PURE__ */ jsxRuntimeExports.jsx("input", { type: "checkbox", className: "sr-only", checked: config.parallelExecution || false, onChange: (e) => { 3417 const checked = e.target.checked; 3418 const next = { ...config, parallelExecution: checked }; 3419 setConfig(next); 3420 handleSaveConfig(next); 3421 for (const node of workerNodes) { 3422 saveWorkerConfig(node.id, node.config.poll_interval, node.config.max_threads, node.config.cpu_threshold, node.config.scale, node.config.tasks_per_cpu, checked, true); 3423 } 3424 } }),
3425 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `block w-10 h-6 rounded-full transition-colors ${config.parallelExecution ? "bg-indigo-500" : "bg-zinc-300 dark:bg-zinc-700"}` }), 3426 /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `absolute left-1 top-1 bg-white w-4 h-4 rounded-full transition-transform ${config.parallelExecution ? "translate-x-4" : ""}` }) 3427 ] }), 3428 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs font-bold text-zinc-900 dark:text-white", children: config.parallelExecution ? "Enabled (Fast)" : "Disabled (Sequential)" }) 3429 ] }) }), 3430 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] text-zinc-400 dark:text-zinc-500 mt-1 leading-tight block", children: "Process independent pipeline steps (like Stems, Audio, Waveforms, Sheet Music) concurrently on a single track. Dramatically speeds up processing but uses more memory per container." }) 3431 ] }),
3432 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3433 "button", 3434 { 3435 onClick: () => handleSaveConfig(), 3436 disabled: isSaving, 3437 className: "w-full py-2.5 bg-indigo-600 hover:bg-indigo-700 text-white rounded-xl text-xs font-bold transition-all flex items-center justify-center gap-2 shadow-sm shadow-indigo-600/10 disabled:opacity-50 mt-2", 3438 children: [ 3439 isSaving ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 14 }), 3440 isSaving ? "Saving Settings..." : "Save Runtime Settings" 3441 ] 3442 } 3443 ), 3444 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-amber-50 dark:bg-amber-900/10 rounded-xl border border-amber-100 dark:border-amber-900/30", children: [ 3445 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-[10px] font-bold text-amber-800 dark:text-amber-200 flex items-center gap-2 mb-2 uppercase", children: [
3446 /* @__PURE__ */ jsxRuntimeExports.jsx(CircleAlert, { size: 14 }), 3447 " Queue & Jobs Management" 3448 ] }), 3449 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [ 3450 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleResetStuck, className: "w-full py-2 bg-white dark:bg-zinc-900 border border-amber-200 dark:border-amber-800 rounded-lg text-xs font-bold text-amber-700 dark:text-amber-300 hover:bg-amber-50 dark:hover:bg-amber-900/20 transition-colors", children: "Reset Stuck & Failed" }), 3451 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "grid grid-cols-2 gap-2", children: [ 3452 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleClearQueue, className: "w-full py-2 bg-white dark:bg-zinc-900 border border-red-200 dark:border-red-800 rounded-lg text-[10px] font-bold text-red-700 dark:text-red-300 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors leading-tight", children: "Clear Queue" }),
3453 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleClearFailures, className: "w-full py-2 bg-white dark:bg-zinc-900 border border-red-200 dark:border-red-800 rounded-lg text-[10px] font-bold text-red-700 dark:text-red-300 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors leading-tight", children: "Clear Failures" }) 3454 ] }), 3455 /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: handleStopAll, className: "w-full py-2 bg-red-600 hover:bg-red-700 active:bg-red-800 text-white rounded-lg text-xs font-bold shadow-md shadow-red-500/10 transition-colors", children: "ð¨ EMERGENCY STOP ALL" }), 3456 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[9px] text-amber-700/80 dark:text-amber-300/70 mt-1 leading-tight", children: "Note: Stuck tasks are auto-recovered (up to 2 attempts). Persistent failures are moved to 'failed' and logged under 'Persistent Processing Failures'." }) 3457 ] }) 3458 ] }), 3459 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-red-50 dark:bg-red-900/10 rounded-xl border border-red-100 dark:border-red-900/30", children: [
3460 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-[10px] font-bold text-red-800 dark:text-red-200 flex items-center gap-2 mb-2 uppercase", children: [ 3461 /* @__PURE__ */ jsxRuntimeExports.jsx(Database, { size: 14 }), 3462 " Storage Cleanup" 3463 ] }), 3464 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[9px] text-red-700 dark:text-red-400 mb-2 leading-tight", children: "Define patterns (comma separated) to prune from scores directory." }), 3465 /* @__PURE__ */ jsxRuntimeExports.jsx( 3466 "textarea", 3467 { 3468 value: cleanupPatterns, 3469 onChange: (e) => setCleanupPatterns(e.target.value), 3470 placeholder: "e.g. *_old.xml, *.tmp", 3471 className: "w-full h-16 p-2 mb-3 bg-white dark:bg-zinc-950 border border-red-100 dark:border-red-900/50 rounded-lg text-[10px] font-mono resize-none focus:outline-none focus:ring-1 focus:ring-red-500/30" 3472 } 3473 ),
3474 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3475 "button", 3476 { 3477 onClick: handleGarbageCollection, 3478 disabled: isCleaning, 3479 className: "w-full py-2 bg-white dark:bg-zinc-900 border border-red-200 dark:border-red-800 rounded-lg text-xs font-bold text-red-700 dark:text-red-300 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors flex items-center justify-center gap-2", 3480 children: [ 3481 isCleaning ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 14, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Scissors, { size: 14 }), 3482 isCleaning ? "Prune Files" : "Run Garbage Collection" 3483 ] 3484 } 3485 ) 3486 ] }), 3487 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-4 bg-zinc-50 dark:bg-zinc-800/20 rounded-xl border border-zinc-200 dark:border-zinc-800/80", children: [ 3488 /* @__PURE__ */ jsxRuntimeExports.jsxs("h4", { className: "text-[10px] font-bold text-zinc-800 dark:text-zinc-200 flex items-center gap-2 mb-2 uppercase", children: [
3489 /* @__PURE__ */ jsxRuntimeExports.jsx(FileHeadphone, { size: 14, className: "text-indigo-500" }), 3490 " MIDI Converter Settings" 3491 ] }), 3492 /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[9px] text-zinc-500 dark:text-zinc-400 mb-3 leading-tight", children: "Configure the retention policy for temporary converted audio files (MP3/Opus/WAV) to control disk storage space." }), 3493 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-3", children: [ 3494 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [ 3495 /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-between items-center mb-1", children: [ 3496 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[9px] font-black uppercase text-zinc-400", children: "Temp File Lifetime" }), 3497 /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-xs font-black text-indigo-600 dark:text-indigo-400", children: [ 3498 converterLifetimeHours, 3499 " hour", 3500 converterLifetimeHours !== 1 ? "s" : "" 3501 ] }) 3502 ] }),
3503 /* @__PURE__ */ jsxRuntimeExports.jsx( 3504 "input", 3505 { 3506 type: "range", 3507 min: "1", 3508 max: "168", 3509 step: "1", 3510 value: converterLifetimeHours, 3511 onChange: (e) => setConverterLifetimeHours(parseInt(e.target.value)), 3512 className: "w-full accent-indigo-600" 3513 } 3514 ), 3515 /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[8px] text-zinc-400 dark:text-zinc-500 mt-1 block", children: "Min: 1 hour, Max: 1 week (168 hours)." }) 3516 ] }), 3517 /* @__PURE__ */ jsxRuntimeExports.jsxs( 3518 "button", 3519 { 3520 onClick: handleSaveConverterConfig, 3521 disabled: isSavingConverterConfig, 3522 className: "w-full py-2 bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 text-white rounded-lg text-xs font-bold transition-all flex items-center justify-center gap-2 shadow-sm", 3523 children: [ 3524 isSavingConverterConfig ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { size: 13, className: "animate-spin" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Save, { size: 13 }), 3525 "Save Retention Policy" 3526 ] 3527 } 3528 ) 3529 ] }) 3530 ] }) 3531 ] }) 3532 ] }) 3533 ] }) 3534 ] }) 3535 ] }); 3536}; 3537export { 3538 WorkerManager as default 3539};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.