Frontend: structured error handling, state fixes, accessibility, i18n
- Enhance fetchWithAuth with auto-401, retry w/ exponential backoff, timeout - Remove ~40 manual 401 checks across 10 feature files - Fix state: brightness cache setter, manual edit flag resets, static import - Add ARIA: role=dialog/tablist, aria-modal, aria-labelledby, aria-selected - Add focus trapping in Modal base class, aria-expanded on hint toggles - Fix WCAG AA color contrast with --primary-text-color variable - Add i18n pluralization (CLDR rules for en/ru), getCurrentLocale export - Replace hardcoded strings in dashboard.js and profiles.js - Add data-i18n-aria-label support, 20 new keys in en.json and ru.json Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
import {
|
||||
calibrationTestState, EDGE_TEST_COLORS,
|
||||
} from '../core/state.js';
|
||||
import { API_BASE, getHeaders, handle401Error } from '../core/api.js';
|
||||
import { API_BASE, getHeaders, fetchWithAuth } from '../core/api.js';
|
||||
import { showToast } from '../core/ui.js';
|
||||
import { Modal } from '../core/modal.js';
|
||||
import { closeTutorial, startCalibrationTutorial } from './tutorials.js';
|
||||
@@ -53,11 +53,10 @@ let _previewRaf = null;
|
||||
export async function showCalibration(deviceId) {
|
||||
try {
|
||||
const [response, displaysResponse] = await Promise.all([
|
||||
fetch(`${API_BASE}/devices/${deviceId}`, { headers: getHeaders() }),
|
||||
fetch(`${API_BASE}/config/displays`, { headers: getHeaders() }),
|
||||
fetchWithAuth(`/devices/${deviceId}`),
|
||||
fetchWithAuth('/config/displays'),
|
||||
]);
|
||||
|
||||
if (response.status === 401) { handle401Error(); return; }
|
||||
if (!response.ok) { showToast('Failed to load calibration', 'error'); return; }
|
||||
|
||||
const device = await response.json();
|
||||
@@ -131,6 +130,7 @@ export async function showCalibration(deviceId) {
|
||||
window._calibrationResizeObserver.observe(preview);
|
||||
|
||||
} catch (error) {
|
||||
if (error.isAuth) return;
|
||||
console.error('Failed to load calibration:', error);
|
||||
showToast('Failed to load calibration', 'error');
|
||||
}
|
||||
@@ -626,18 +626,17 @@ export async function toggleTestEdge(edge) {
|
||||
updateCalibrationPreview();
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/devices/${deviceId}/calibration/test`, {
|
||||
const response = await fetchWithAuth(`/devices/${deviceId}/calibration/test`, {
|
||||
method: 'PUT',
|
||||
headers: getHeaders(),
|
||||
body: JSON.stringify({ edges })
|
||||
});
|
||||
if (response.status === 401) { handle401Error(); return; }
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
error.textContent = `Test failed: ${errorData.detail}`;
|
||||
error.style.display = 'block';
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.isAuth) return;
|
||||
console.error('Failed to toggle test edge:', err);
|
||||
error.textContent = 'Failed to toggle test edge';
|
||||
error.style.display = 'block';
|
||||
@@ -696,12 +695,10 @@ export async function saveCalibration() {
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/devices/${deviceId}/calibration`, {
|
||||
const response = await fetchWithAuth(`/devices/${deviceId}/calibration`, {
|
||||
method: 'PUT',
|
||||
headers: getHeaders(),
|
||||
body: JSON.stringify(calibration)
|
||||
});
|
||||
if (response.status === 401) { handle401Error(); return; }
|
||||
if (response.ok) {
|
||||
showToast('Calibration saved', 'success');
|
||||
calibModal.forceClose();
|
||||
@@ -712,6 +709,7 @@ export async function saveCalibration() {
|
||||
error.style.display = 'block';
|
||||
}
|
||||
} catch (err) {
|
||||
if (err.isAuth) return;
|
||||
console.error('Failed to save calibration:', err);
|
||||
error.textContent = 'Failed to save calibration';
|
||||
error.style.display = 'block';
|
||||
|
||||
Reference in New Issue
Block a user