From d29bd1d76bdf208f7bba62b137f5029aec214151 Mon Sep 17 00:00:00 2001 From: jedarden Date: Wed, 15 Apr 2026 14:32:18 -0400 Subject: [PATCH] Add live install log panel to flash step Captures console.log/warn/error and esp-web-tools state-changed events into a scrollable monospace log panel (collapsed by default, auto-opens on flash-start and flash-error). Includes timestamps and error detail from the flash-error event for diagnosing failures like the toString crash. Co-Authored-By: Claude Sonnet 4.6 --- dashboard/js/onboard.js | 55 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/dashboard/js/onboard.js b/dashboard/js/onboard.js index dbc3fee..d032639 100644 --- a/dashboard/js/onboard.js +++ b/dashboard/js/onboard.js @@ -394,6 +394,35 @@ function renderFlashFirmware(contentEl) { var flashRetryCount = 0; + var flashLogs = []; + var origConsole = { log: console.log, warn: console.warn, error: console.error }; + + function appendLog(level, args) { + var msg = Array.prototype.slice.call(args).map(function (a) { + try { return (typeof a === 'object') ? JSON.stringify(a) : String(a); } catch (e) { return String(a); } + }).join(' '); + var ts = new Date().toISOString().slice(11, 23); + flashLogs.push({ level: level, ts: ts, msg: msg }); + var logEl = document.getElementById('flash-log-body'); + if (logEl) { + var color = level === 'error' ? '#ef9a9a' : level === 'warn' ? '#ffe082' : '#b0bec5'; + var line = document.createElement('div'); + line.style.cssText = 'font-size:11px;color:' + color + ';word-break:break-all;margin:1px 0'; + line.textContent = '[' + ts + '] ' + msg; + logEl.appendChild(line); + logEl.scrollTop = logEl.scrollHeight; + } + } + + function patchConsole() { + ['log', 'warn', 'error'].forEach(function (m) { + console[m] = function () { origConsole[m].apply(console, arguments); appendLog(m, arguments); }; + }); + } + + function restoreConsole() { + ['log', 'warn', 'error'].forEach(function (m) { console[m] = origConsole[m]; }); + } contentEl.innerHTML = '
' + @@ -416,11 +445,19 @@ '

Preparing...

' + '
' + '' + + '
' + + 'Show install log' + + '
' + + '
' + ''; hideNav(); + patchConsole(); + appendLog('log', ['Flash step loaded']); // Check esp-web-tools is loaded if (!customElements.get('esp-web-install-button')) { + restoreConsole(); document.getElementById('flash-container').innerHTML = '

Firmware flashing component failed to load. ' + 'Please refresh the page and ensure you have a stable internet connection.

'; @@ -440,12 +477,19 @@ (flashRetryCount > 0 ? 'Try Again' : 'Start Flashing') + ''; container.appendChild(installBtn); + installBtn.addEventListener('state-changed', function (e) { + var s = (e.detail || {}).state; + if (s) { appendLog('log', ['state: ' + s]); } + }); + installBtn.addEventListener('flash-start', function () { + appendLog('log', ['flash-start']); document.getElementById('flash-progress').style.display = 'block'; document.getElementById('flash-status').textContent = 'Flashing...'; document.getElementById('flash-progress-fill').style.width = '0%'; container.style.display = 'none'; document.getElementById('flash-recovery').style.display = 'none'; + document.getElementById('flash-log-details').open = true; }); installBtn.addEventListener('flash-progress', function (e) { @@ -457,6 +501,8 @@ }); installBtn.addEventListener('flash-success', function () { + appendLog('log', ['flash-success']); + restoreConsole(); document.getElementById('flash-progress').style.display = 'none'; container.innerHTML = '

✓ Firmware flashed successfully!

'; container.style.display = 'block'; @@ -464,20 +510,23 @@ setTimeout(function () { goToStep(state.currentStepIndex + 1); }, 1500); }); - installBtn.addEventListener('flash-error', function () { + installBtn.addEventListener('flash-error', function (e) { flashRetryCount++; + var errDetail = ''; + try { errDetail = JSON.stringify(e.detail || {}); } catch (_) { errDetail = String(e.detail); } + appendLog('error', ['flash-error detail=' + errDetail]); + document.getElementById('flash-log-details').open = true; document.getElementById('flash-progress').style.display = 'none'; container.style.display = 'block'; var recovery = document.getElementById('flash-recovery'); recovery.style.display = 'block'; recovery.innerHTML = renderBootloaderHelp(flashRetryCount); - // Rebuild the button so it can be clicked again mountInstallButton(); }); } mountInstallButton(); - return { cleanup: function () { } }; + return { cleanup: restoreConsole }; } function renderProvisionWifi(contentEl) {