fix(error): harden logging, i18n, a11y and handler tests

This commit is contained in:
2026-03-24 22:00:14 +01:00
parent 44a357dfc4
commit a0d816caaa
10 changed files with 515 additions and 100 deletions

View File

@@ -156,6 +156,10 @@ body.app-error-debug {
.app-error-debug-copy-button:hover { color: var(--app-color); }
.app-error-debug-copy-button.copied { color: var(--app-primary); }
.app-error-debug-copy-button:focus-visible {
outline: 2px solid var(--app-primary);
outline-offset: 2px;
}
/* ── Exception Summary ───────────────────────────────────────────────── */
@@ -206,6 +210,10 @@ body.app-error-debug {
}
.app-error-debug-tab:hover { color: var(--app-color); }
.app-error-debug-tab:focus-visible {
outline: 2px solid var(--app-primary);
outline-offset: 2px;
}
.app-error-debug-tab.active {
color: var(--app-primary);
@@ -251,11 +259,18 @@ body.app-error-debug {
cursor: pointer;
background: var(--app-card-background-color);
transition: background var(--app-transition);
width: 100%;
border: 0;
text-align: left;
}
.app-error-debug-frame__header:hover {
background: var(--app-card-sectioning-background-color);
}
.app-error-debug-frame__header:focus-visible {
outline: 2px solid var(--app-primary);
outline-offset: -2px;
}
.app-error-debug-frame__index {
color: var(--app-muted-color);
@@ -385,6 +400,19 @@ body.app-error-debug {
cursor: pointer;
font-family: var(--app-font-family-monospace);
font-size: var(--text-xs);
width: 100%;
border: 0;
text-align: left;
background: transparent;
}
.app-error-debug-query__header:hover {
background: var(--app-card-sectioning-background-color);
}
.app-error-debug-query__header:focus-visible {
outline: 2px solid var(--app-primary);
outline-offset: -2px;
}
.app-error-debug-query__duration {

View File

@@ -5,32 +5,74 @@ document.addEventListener('DOMContentLoaded', () => {
const tabs = document.querySelectorAll('.app-error-debug-tab');
const panels = document.querySelectorAll('.app-error-debug-panel');
const activateTab = (tab) => {
const target = tab.dataset.panel;
tabs.forEach(t => t.classList.remove('active'));
tabs.forEach(t => t.setAttribute('aria-selected', 'false'));
tabs.forEach(t => t.setAttribute('tabindex', '-1'));
panels.forEach(p => p.classList.remove('active'));
tab.classList.add('active');
tab.setAttribute('aria-selected', 'true');
tab.setAttribute('tabindex', '0');
const panel = document.getElementById(target);
if (panel) panel.classList.add('active');
};
tabs.forEach(tab => {
tab.addEventListener('click', () => {
const target = tab.dataset.panel;
tabs.forEach(t => t.classList.remove('active'));
panels.forEach(p => p.classList.remove('active'));
tab.classList.add('active');
const panel = document.getElementById(target);
if (panel) panel.classList.add('active');
activateTab(tab);
});
tab.addEventListener('keydown', (event) => {
if (tabs.length === 0) return;
const currentIndex = Array.prototype.indexOf.call(tabs, tab);
if (currentIndex < 0) return;
let nextIndex = currentIndex;
if (event.key === 'ArrowRight') {
nextIndex = (currentIndex + 1) % tabs.length;
} else if (event.key === 'ArrowLeft') {
nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;
} else if (event.key === 'Home') {
nextIndex = 0;
} else if (event.key === 'End') {
nextIndex = tabs.length - 1;
} else {
return;
}
event.preventDefault();
const nextTab = tabs[nextIndex];
if (!nextTab) return;
activateTab(nextTab);
nextTab.focus();
});
});
// ── Frame expand/collapse ──────────────────────────
document.querySelectorAll('.app-error-debug-frame__header').forEach(header => {
header.addEventListener('click', () => {
header.closest('.app-error-debug-frame')?.classList.toggle('open');
document.querySelectorAll('.app-error-debug-frame__toggle').forEach(toggle => {
toggle.addEventListener('click', () => {
const frame = toggle.closest('.app-error-debug-frame');
if (!frame) return;
const isOpen = frame.classList.toggle('open');
toggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
});
});
// Open the first frame by default.
const firstFrame = document.querySelector('.app-error-debug-frame');
if (firstFrame) firstFrame.classList.add('open');
// Ensure ARIA reflects initial state.
document.querySelectorAll('.app-error-debug-frame').forEach(frame => {
const toggle = frame.querySelector('.app-error-debug-frame__toggle');
if (!toggle) return;
toggle.setAttribute('aria-expanded', frame.classList.contains('open') ? 'true' : 'false');
});
// ── Query expand/collapse ──────────────────────────
document.querySelectorAll('.app-error-debug-query__header').forEach(header => {
header.addEventListener('click', () => {
header.closest('.app-error-debug-query')?.classList.toggle('open');
document.querySelectorAll('.app-error-debug-query__toggle').forEach(toggle => {
toggle.addEventListener('click', () => {
const query = toggle.closest('.app-error-debug-query');
if (!query) return;
const isOpen = query.classList.toggle('open');
toggle.setAttribute('aria-expanded', isOpen ? 'true' : 'false');
});
});