From a2a4806c47ff403ea12c6fd828d656de6c4c85d5 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Sat, 14 Feb 2026 04:24:15 -0600 Subject: [PATCH] feat: Add debug console panel for mobile debugging Replace ConnectionDropdown with debug console button that intercepts console.log/warn/error and displays them in an overlay panel. Allows copying logs for debugging on mobile devices without dev tools. --- frontend/src/App.vue | 231 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 229 insertions(+), 2 deletions(-) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 18c3bdc..4128f4d 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -5,7 +5,7 @@ import StatusBar from './components/StatusBar.vue' import Toolbar from './components/Toolbar.vue' import ComponentsDropdown from './components/ComponentsDropdown.vue' import ToolsDropdown from './components/ToolsDropdown.vue' -import ConnectionDropdown from './components/ConnectionDropdown.vue' +// ConnectionDropdown removed - replaced with debug console import FloatingTerminal from './components/FloatingTerminal.vue' import FloatingResponse from './components/FloatingResponse.vue' import FloatingVoice from './components/FloatingVoice.vue' @@ -21,6 +21,46 @@ const route = useRoute() const router = useRouter() const showTerminal = ref(false) const showVoice = ref(false) +const showDebugConsole = ref(false) +const debugLogs = ref>([]) + +// Intercept console.log for debug panel +const originalConsoleLog = console.log +const originalConsoleWarn = console.warn +const originalConsoleError = console.error + +function addDebugLog(type: string, args: any[]) { + const message = args.map(a => typeof a === 'object' ? JSON.stringify(a) : String(a)).join(' ') + const time = new Date().toLocaleTimeString() + debugLogs.value.push({ type, message, time }) + // Keep only last 100 logs + if (debugLogs.value.length > 100) { + debugLogs.value.shift() + } +} + +console.log = (...args) => { + originalConsoleLog.apply(console, args) + addDebugLog('log', args) +} +console.warn = (...args) => { + originalConsoleWarn.apply(console, args) + addDebugLog('warn', args) +} +console.error = (...args) => { + originalConsoleError.apply(console, args) + addDebugLog('error', args) +} + +function copyDebugLogs() { + const text = debugLogs.value.map(l => `[${l.time}] [${l.type}] ${l.message}`).join('\n') + navigator.clipboard.writeText(text) + canvasStore.showNotification('Logs copied!', 'success') +} + +function clearDebugLogs() { + debugLogs.value = [] +} const terminalRef = ref | null>(null) const responseRef = ref | null>(null) const canvasStore = useCanvasStore() @@ -265,7 +305,12 @@ watch(() => route.name, (newPage) => {

Agent UI

- + @@ -393,6 +438,36 @@ watch(() => route.name, (newPage) => { + + + + +
+
+ Debug Console ({{ debugLogs.length }}) +
+ + + +
+
+
+
+ {{ log.time }} + {{ log.type }} + {{ log.message }} +
+
No logs yet
+
+
+
+
@@ -915,4 +990,156 @@ watch(() => route.name, (newPage) => { bottom: calc(10vh + 16px); } } + +/* Debug Console Button */ +.debug-btn { + display: flex; + align-items: center; + gap: 4px; + padding: 4px 8px; + background: rgba(100, 100, 100, 0.2); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 6px; + color: #888; + font-size: 11px; + cursor: pointer; + transition: all 0.2s; +} + +.debug-btn:hover { + background: rgba(100, 100, 100, 0.3); + color: #aaa; +} + +.debug-btn.active { + background: rgba(59, 130, 246, 0.3); + border-color: rgba(59, 130, 246, 0.5); + color: #60a5fa; +} + +.log-count { + background: #ef4444; + color: white; + font-size: 9px; + padding: 1px 5px; + border-radius: 10px; + min-width: 16px; + text-align: center; +} + +/* Debug Console Panel */ +.debug-console { + position: fixed; + top: 50px; + left: 10px; + right: 10px; + bottom: 80px; + background: rgba(20, 20, 25, 0.98); + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px; + z-index: 10002; + display: flex; + flex-direction: column; + backdrop-filter: blur(10px); + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5); +} + +.debug-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 14px; + background: rgba(255, 255, 255, 0.05); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 12px 12px 0 0; + color: #ddd; + font-size: 12px; + font-weight: 600; +} + +.debug-actions { + display: flex; + gap: 8px; +} + +.debug-actions button { + padding: 4px 10px; + background: rgba(255, 255, 255, 0.1); + border: none; + border-radius: 4px; + color: #aaa; + font-size: 11px; + cursor: pointer; +} + +.debug-actions button:hover { + background: rgba(255, 255, 255, 0.2); + color: #fff; +} + +.debug-logs { + flex: 1; + overflow-y: auto; + padding: 8px; + font-family: 'Consolas', 'Monaco', monospace; + font-size: 11px; +} + +.debug-log { + display: flex; + gap: 8px; + padding: 6px 8px; + border-radius: 4px; + cursor: pointer; + border-bottom: 1px solid rgba(255, 255, 255, 0.03); +} + +.debug-log:hover { + background: rgba(255, 255, 255, 0.05); +} + +.debug-log:active { + background: rgba(59, 130, 246, 0.2); +} + +.log-time { + color: #666; + flex-shrink: 0; +} + +.log-type { + width: 40px; + flex-shrink: 0; + font-weight: 600; +} + +.debug-log.log .log-type { color: #888; } +.debug-log.warn .log-type { color: #f59e0b; } +.debug-log.error .log-type { color: #ef4444; } + +.log-msg { + color: #ccc; + word-break: break-all; +} + +.debug-log.warn .log-msg { color: #fcd34d; } +.debug-log.error .log-msg { color: #fca5a5; } + +.debug-empty { + color: #666; + text-align: center; + padding: 40px; +} + +/* Debug slide animation */ +.debug-slide-enter-active, +.debug-slide-leave-active { + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); +} + +.debug-slide-enter-from, +.debug-slide-leave-to { + opacity: 0; + transform: translateY(-20px); +}