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
? ``
: '';
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);
});