Add session error log and transient error icon

This commit is contained in:
Jordan Wages 2026-01-06 22:01:20 -06:00
commit 9269225a0c
4 changed files with 135 additions and 15 deletions

View file

@ -51,6 +51,7 @@
<li class="is-active" data-tab="settings"><a><span class="icon is-small"><img data-icon="settings" data-size="16" src="../resources/img/settings-light-16.png" alt=""></span><span>Settings</span></a></li>
<li data-tab="rules"><a><span class="icon is-small"><img data-icon="clipboarddata" data-size="16" src="../resources/img/clipboarddata-light-16.png" alt=""></span><span>Rules</span></a></li>
<li data-tab="maintenance"><a><span class="icon is-small"><img data-icon="gear" data-size="16" src="../resources/img/gear-light-16.png" alt=""></span><span>Maintenance</span></a></li>
<li id="errors-tab-button" class="is-hidden" data-tab="errors"><a><span class="icon is-small"><img data-icon="x" data-size="16" src="../resources/img/x-light-16.png" alt=""></span><span>Errors</span></a></li>
<li id="debug-tab-button" class="is-hidden" data-tab="debug"><a><span class="icon is-small"><img data-icon="average" data-size="16" src="../resources/img/average-light-16.png" alt=""></span><span>Debug</span></a></li>
</ul>
</div>
@ -285,6 +286,32 @@
</div>
</div>
<div id="errors-tab" class="tab-content is-hidden">
<h2 class="title is-4">
<span class="icon is-small"><img data-icon="x" data-size="16" src="../resources/img/x-light-16.png" alt=""></span>
<span>Session Errors</span>
</h2>
<div id="errors-empty" class="notification is-success is-light">
No errors have been recorded since the last start.
</div>
<div id="errors-panel" class="is-hidden">
<div class="box mb-4">
<div class="level">
<div class="level-left">
<div>
<p class="title is-5 mb-1">Error Log</p>
<p class="subtitle is-6">Visible only for this session.</p>
</div>
</div>
<div class="level-right">
<span class="tag is-danger is-light" id="errors-count">0</span>
</div>
</div>
</div>
<div id="errors-list"></div>
</div>
</div>
<div id="debug-tab" class="tab-content is-hidden">
<h2 class="title is-4">
<span class="icon is-small"><img data-icon="average" data-size="16" src="../resources/img/average-light-16.png" alt=""></span>

View file

@ -196,6 +196,11 @@ document.addEventListener('DOMContentLoaded', async () => {
const debugTabToggle = document.getElementById('show-debug-tab');
const debugTabBtn = document.getElementById('debug-tab-button');
const errorTabBtn = document.getElementById('errors-tab-button');
const errorsEmpty = document.getElementById('errors-empty');
const errorsPanel = document.getElementById('errors-panel');
const errorsList = document.getElementById('errors-list');
const errorsCount = document.getElementById('errors-count');
function updateDebugTab() {
const visible = debugTabToggle.checked;
debugTabBtn.classList.toggle('is-hidden', !visible);
@ -204,6 +209,71 @@ document.addEventListener('DOMContentLoaded', async () => {
debugTabToggle.addEventListener('change', () => { updateDebugTab(); markDirty(); });
updateDebugTab();
function formatErrorTime(value) {
try {
return new Date(value).toLocaleString();
} catch (e) {
return '';
}
}
function renderErrors(entries = []) {
const hasErrors = entries.length > 0;
errorTabBtn.classList.toggle('is-hidden', !hasErrors);
errorsEmpty.classList.toggle('is-hidden', hasErrors);
errorsPanel.classList.toggle('is-hidden', !hasErrors);
errorsList.innerHTML = '';
errorsCount.textContent = String(entries.length);
if (!hasErrors) {
return;
}
entries.forEach(entry => {
const card = document.createElement('article');
card.className = 'message is-danger is-light mb-4';
const header = document.createElement('div');
header.className = 'message-header';
const title = document.createElement('p');
title.textContent = entry.context || 'Error';
const time = document.createElement('span');
time.className = 'is-size-7 has-text-weight-normal';
time.textContent = formatErrorTime(entry.time);
header.appendChild(title);
header.appendChild(time);
const body = document.createElement('div');
body.className = 'message-body';
const summary = document.createElement('p');
summary.className = 'mb-2';
summary.textContent = entry.message || 'Unknown error';
body.appendChild(summary);
if (entry.detail) {
const detail = document.createElement('pre');
detail.className = 'is-family-monospace is-size-7';
detail.textContent = entry.detail;
body.appendChild(detail);
}
card.appendChild(header);
card.appendChild(body);
errorsList.appendChild(card);
});
}
async function loadErrors() {
try {
const response = await browser.runtime.sendMessage({ type: 'sortana:getErrorLog' });
renderErrors(response?.errors || []);
} catch (e) {
renderErrors([]);
}
}
browser.runtime.onMessage.addListener((msg) => {
if (msg?.type === 'sortana:errorLogUpdated') {
loadErrors();
}
});
await loadErrors();
updateDiffDisplay();
[htmlToggle, stripUrlToggle, altTextToggle, collapseWhitespaceToggle, tokenReductionToggle].forEach(toggle => {