const TYPE_LABELS = { GENERATE_IMAGE: 'GEN IMAGE', REGENERATE_IMAGE: 'REGEN IMAGE', EDIT_IMAGE: 'EDIT IMAGE', GENERATE_CHARACTER_IMAGE: 'GEN REF', REGENERATE_CHARACTER_IMAGE: 'REGEN REF', EDIT_CHARACTER_IMAGE: 'EDIT REF', GENERATE_VIDEO: 'GEN VIDEO', GENERATE_VIDEO_REFS: 'GEN VIDEO FROM REFS', UPSCALE_VIDEO: 'UPSCALE VIDEO', GEN_IMG: 'GEN IMAGE', GEN_VID: 'GEN VIDEO', GEN_VID_REF: 'GEN VIDEO FROM REFS', UPSCALE: 'UPSCALE VIDEO', TRACKING: 'TRACKING', URL_REFRESH: 'URL REFRESH', }; function formatType(type) { if (!type) return '—'; return TYPE_LABELS[type] || type.slice(0, 12).toUpperCase(); } function formatTime(iso) { if (!iso) return '—'; try { const d = new Date(iso); const hh = String(d.getHours()).padStart(2, '0'); const mm = String(d.getMinutes()).padStart(2, '0'); const ss = String(d.getSeconds()).padStart(2, '0'); return `${hh}:${mm}:${ss}`; } catch { return '—'; } } function escHtml(str) { return String(str) .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); } function badgeHtml(status) { if (status === 'COMPLETED' || status === 'success') { return '✓ done'; } else if (status === 'FAILED' || status === 'failed' || (typeof status === 'number' && status >= 400)) { return '✗ fail'; } else if (status === 'PROCESSING') { return '⏳ gen...'; } else { return '⏳ sent'; } } function renderLog(entries) { const list = document.getElementById('log-list'); const countEl = document.getElementById('log-count'); if (!entries || entries.length === 0) { list.innerHTML = '
No requests yet
'; countEl.textContent = '0'; return; } countEl.textContent = entries.length; list.innerHTML = entries.map((entry, i) => { const shortId = entry.id ? String(entry.id).slice(0, 8) : '—'; const type = formatType(entry.type || entry.method); const time = formatTime(entry.time || entry.timestamp); const status = entry.status || 'pending'; const error = entry.error || ''; const urlDisplay = entry.url ? `
URL
${escHtml(entry.url)}
` : ''; const payloadDisplay = entry.payloadSummary ? `
Payload
${escHtml(entry.payloadSummary)}
` : ''; const responseDisplay = entry.responseSummary ? `
Response${entry.httpStatus ? ` (${entry.httpStatus})` : ''}
${escHtml(entry.responseSummary)}
` : ''; const errorDisplay = error ? `
Error
${escHtml(error)}
` : ''; const hasDetails = entry.url || entry.payloadSummary || entry.responseSummary || error; return `
${escHtml(shortId)} ${escHtml(type)} ${escHtml(time)} ${badgeHtml(status)} ${hasDetails ? '' : ''}
${hasDetails ? `
${urlDisplay}${payloadDisplay}${responseDisplay}${errorDisplay}
` : ''}
`; }).join(''); // Toggle expand on row click list.querySelectorAll('.entry-row').forEach((row) => { row.addEventListener('click', () => { const entry = row.closest('.entry'); if (entry.querySelector('.entry-details')) { entry.classList.toggle('open'); } }); }); } document.getElementById('btn-panel').addEventListener('click', () => { chrome.windows.getCurrent((win) => { chrome.sidePanel.open({ windowId: win.id }); }); }); chrome.runtime.sendMessage({ type: 'REQUEST_LOG' }, (data) => { if (chrome.runtime.lastError) return; if (data && data.log) renderLog(data.log); });