From 2212f0b736f209d599780877ae724ded4182d842 Mon Sep 17 00:00:00 2001 From: hobokenchicken Date: Mon, 2 Mar 2026 13:39:33 -0500 Subject: [PATCH] debug(dashboard): add visible API debug panel to diagnose fetch failures in browser API endpoints return valid data via curl but browser JS shows 'Failed to load'. Added verbose logging and a fixed-position debug panel to api.js that displays the exact error type (JSON parse, API error, or network exception) on-page. Bumped cache-bust to ?v=4. --- static/index.html | 30 +++++++++++++++--------------- static/js/api.js | 42 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/static/index.html b/static/index.html index bedb76f2..f73cb3e4 100644 --- a/static/index.html +++ b/static/index.html @@ -4,7 +4,7 @@ LLM Proxy Gateway - Admin Dashboard - + @@ -166,19 +166,19 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + \ No newline at end of file diff --git a/static/js/api.js b/static/js/api.js index ad7a6b1a..1ef094a2 100644 --- a/static/js/api.js +++ b/static/js/api.js @@ -18,24 +18,62 @@ class ApiClient { } try { + console.log(`[API] Fetching ${url}...`); const response = await fetch(url, { ...options, headers }); - const result = await response.json(); + console.log(`[API] ${url} → status=${response.status} ok=${response.ok} type=${response.headers.get('content-type')}`); + + const text = await response.text(); + console.log(`[API] ${url} → body length=${text.length}, first 200 chars:`, text.substring(0, 200)); + + let result; + try { + result = JSON.parse(text); + } catch (parseErr) { + const msg = `JSON parse failed for ${url}: ${parseErr.message}. Body: ${text.substring(0, 300)}`; + console.error(`[API] ${msg}`); + this._addDebugEntry(url, 'JSON_PARSE_ERROR', msg); + throw new Error(msg); + } if (!response.ok || !result.success) { + const msg = `API error for ${url}: ok=${response.ok} success=${result.success} error=${result.error} status=${response.status}`; + console.error(`[API] ${msg}`); + this._addDebugEntry(url, 'API_ERROR', msg); throw new Error(result.error || `HTTP error! status: ${response.status}`); } + console.log(`[API] ${url} → SUCCESS, data keys:`, result.data ? Object.keys(result.data) : 'null'); return result.data; } catch (error) { - console.error(`API Request failed (${path}):`, error); + console.error(`[API] Request failed (${path}):`, error); + this._addDebugEntry(url, 'EXCEPTION', error.message); throw error; } } + // Visible on-page debug panel for diagnosing fetch failures + _addDebugEntry(url, status, detail) { + let panel = document.getElementById('api-debug-panel'); + if (!panel) { + panel = document.createElement('div'); + panel.id = 'api-debug-panel'; + panel.style.cssText = 'position:fixed;bottom:0;left:0;right:0;max-height:200px;overflow-y:auto;background:#1d2021;color:#fbf1c7;font-family:monospace;font-size:11px;padding:8px;z-index:99999;border-top:2px solid #cc241d;'; + const title = document.createElement('div'); + title.style.cssText = 'font-weight:bold;margin-bottom:4px;color:#fb4934;'; + title.textContent = 'API Debug Panel (remove after fixing)'; + panel.appendChild(title); + document.body.appendChild(panel); + } + const entry = document.createElement('div'); + entry.style.cssText = 'margin:2px 0;padding:2px 4px;background:#282828;border-left:3px solid ' + (status === 'EXCEPTION' ? '#fb4934' : '#fabd2f') + ';'; + entry.textContent = `[${status}] ${url}: ${detail}`; + panel.appendChild(entry); + } + async get(path) { return this.request(path, { method: 'GET' }); }