Show backend error details in toast notifications

Use error.detail from API responses instead of generic i18n messages
so users see specific reasons for failures (e.g. "Device is referenced
by target(s): ...").

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 22:11:24 +03:00
parent 9b2ccde8a7
commit 493d96d604
5 changed files with 10 additions and 14 deletions

View File

@@ -735,7 +735,7 @@ export async function dashboardStartTarget(targetId) {
loadDashboard();
} else {
const error = await response.json();
showToast(t('dashboard.error.start_failed'), 'error');
showToast(error.detail || t('dashboard.error.start_failed'), 'error');
}
} catch (error) {
if (error.isAuth) return;
@@ -753,7 +753,7 @@ export async function dashboardStopTarget(targetId) {
loadDashboard();
} else {
const error = await response.json();
showToast(t('dashboard.error.stop_failed'), 'error');
showToast(error.detail || t('dashboard.error.stop_failed'), 'error');
}
} catch (error) {
if (error.isAuth) return;
@@ -772,7 +772,7 @@ export async function dashboardToggleAutoStart(targetId, enable) {
loadDashboard();
} else {
const error = await response.json();
showToast(t('dashboard.error.autostart_toggle_failed'), 'error');
showToast(error.detail || t('dashboard.error.autostart_toggle_failed'), 'error');
}
} catch (error) {
if (error.isAuth) return;

View File

@@ -150,7 +150,7 @@ export async function removeDevice(deviceId) {
window.loadDevices();
} else {
const error = await response.json();
showToast(t('device.error.remove_failed'), 'error');
showToast(error.detail || t('device.error.remove_failed'), 'error');
}
} catch (error) {
if (error.isAuth) return;

View File

@@ -611,7 +611,7 @@ export async function deleteKCTarget(targetId) {
if (typeof window.loadTargetsTab === 'function') window.loadTargetsTab();
} else {
const error = await response.json();
showToast(t('kc_target.error.delete_failed'), 'error');
showToast(error.detail || t('kc_target.error.delete_failed'), 'error');
}
} catch (error) {
if (error.isAuth) return;

View File

@@ -210,16 +210,12 @@ export async function deletePatternTemplate(templateId) {
const response = await fetchWithAuth(`/pattern-templates/${templateId}`, {
method: 'DELETE',
});
if (response.status === 409) {
showToast(t('pattern.delete.referenced'), 'error');
return;
}
if (response.ok) {
showToast(t('pattern.deleted'), 'success');
if (typeof window.loadTargetsTab === 'function') window.loadTargetsTab();
} else {
const error = await response.json();
showToast(t('pattern.error.delete_failed'), 'error');
showToast(error.detail || t('pattern.error.delete_failed'), 'error');
}
} catch (error) {
if (error.isAuth) return;

View File

@@ -964,7 +964,7 @@ export async function startTargetProcessing(targetId) {
showToast(t('device.started'), 'success');
} else {
const error = await response.json();
showToast(t('target.error.start_failed'), 'error');
showToast(error.detail || t('target.error.start_failed'), 'error');
}
});
}
@@ -978,7 +978,7 @@ export async function stopTargetProcessing(targetId) {
showToast(t('device.stopped'), 'success');
} else {
const error = await response.json();
showToast(t('target.error.stop_failed'), 'error');
showToast(error.detail || t('target.error.stop_failed'), 'error');
}
});
}
@@ -1034,7 +1034,7 @@ export async function toggleTargetAutoStart(targetId, enable) {
loadTargetsTab();
} else {
const error = await response.json();
showToast(t('target.error.autostart_toggle_failed'), 'error');
showToast(error.detail || t('target.error.autostart_toggle_failed'), 'error');
}
} catch (error) {
console.error('Failed to toggle auto-start:', error);
@@ -1054,7 +1054,7 @@ export async function deleteTarget(targetId) {
showToast(t('targets.deleted'), 'success');
} else {
const error = await response.json();
showToast(t('target.error.delete_failed'), 'error');
showToast(error.detail || t('target.error.delete_failed'), 'error');
}
});
}