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:
@@ -14,7 +14,7 @@ import {
|
||||
PATTERN_RECT_COLORS,
|
||||
PATTERN_RECT_BORDERS,
|
||||
} from '../core/state.js';
|
||||
import { API_BASE, getHeaders, fetchWithAuth, escapeHtml, handle401Error } from '../core/api.js';
|
||||
import { API_BASE, getHeaders, fetchWithAuth, escapeHtml } from '../core/api.js';
|
||||
import { t } from '../core/i18n.js';
|
||||
import { showToast, showConfirm } from '../core/ui.js';
|
||||
import { Modal } from '../core/modal.js';
|
||||
@@ -89,13 +89,13 @@ export async function showPatternTemplateEditor(templateId = null) {
|
||||
document.getElementById('pattern-template-id').value = tmpl.id;
|
||||
document.getElementById('pattern-template-name').value = tmpl.name;
|
||||
document.getElementById('pattern-template-description').value = tmpl.description || '';
|
||||
document.getElementById('pattern-template-title').textContent = t('pattern.edit');
|
||||
document.getElementById('pattern-template-modal-title').textContent = t('pattern.edit');
|
||||
setPatternEditorRects((tmpl.rectangles || []).map(r => ({ ...r })));
|
||||
} else {
|
||||
document.getElementById('pattern-template-id').value = '';
|
||||
document.getElementById('pattern-template-name').value = '';
|
||||
document.getElementById('pattern-template-description').value = '';
|
||||
document.getElementById('pattern-template-title').textContent = t('pattern.add');
|
||||
document.getElementById('pattern-template-modal-title').textContent = t('pattern.add');
|
||||
setPatternEditorRects([]);
|
||||
}
|
||||
|
||||
@@ -148,16 +148,15 @@ export async function savePatternTemplate() {
|
||||
try {
|
||||
let response;
|
||||
if (templateId) {
|
||||
response = await fetch(`${API_BASE}/pattern-templates/${templateId}`, {
|
||||
method: 'PUT', headers: getHeaders(), body: JSON.stringify(payload),
|
||||
response = await fetchWithAuth(`/pattern-templates/${templateId}`, {
|
||||
method: 'PUT', body: JSON.stringify(payload),
|
||||
});
|
||||
} else {
|
||||
response = await fetch(`${API_BASE}/pattern-templates`, {
|
||||
method: 'POST', headers: getHeaders(), body: JSON.stringify(payload),
|
||||
response = await fetchWithAuth('/pattern-templates', {
|
||||
method: 'POST', body: JSON.stringify(payload),
|
||||
});
|
||||
}
|
||||
|
||||
if (response.status === 401) { handle401Error(); return; }
|
||||
if (!response.ok) {
|
||||
const err = await response.json();
|
||||
throw new Error(err.detail || 'Failed to save');
|
||||
@@ -168,6 +167,7 @@ export async function savePatternTemplate() {
|
||||
// Use window.* to avoid circular import with targets.js
|
||||
if (typeof window.loadTargetsTab === 'function') window.loadTargetsTab();
|
||||
} catch (error) {
|
||||
if (error.isAuth) return;
|
||||
console.error('Error saving pattern template:', error);
|
||||
patternModal.showError(error.message);
|
||||
}
|
||||
@@ -178,10 +178,9 @@ export async function deletePatternTemplate(templateId) {
|
||||
if (!confirmed) return;
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/pattern-templates/${templateId}`, {
|
||||
method: 'DELETE', headers: getHeaders(),
|
||||
const response = await fetchWithAuth(`/pattern-templates/${templateId}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (response.status === 401) { handle401Error(); return; }
|
||||
if (response.status === 409) {
|
||||
showToast(t('pattern.delete.referenced'), 'error');
|
||||
return;
|
||||
@@ -194,6 +193,7 @@ export async function deletePatternTemplate(templateId) {
|
||||
showToast(`Failed to delete: ${error.detail}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
if (error.isAuth) return;
|
||||
showToast('Failed to delete pattern template', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user