From 493d96d604fc36ab5b9270a062ed1aa53980e483 Mon Sep 17 00:00:00 2001 From: "alexei.dolgolyov" Date: Sat, 28 Feb 2026 22:11:24 +0300 Subject: [PATCH] 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 --- .../src/wled_controller/static/js/features/dashboard.js | 6 +++--- server/src/wled_controller/static/js/features/devices.js | 2 +- .../src/wled_controller/static/js/features/kc-targets.js | 2 +- .../static/js/features/pattern-templates.js | 6 +----- server/src/wled_controller/static/js/features/targets.js | 8 ++++---- 5 files changed, 10 insertions(+), 14 deletions(-) diff --git a/server/src/wled_controller/static/js/features/dashboard.js b/server/src/wled_controller/static/js/features/dashboard.js index 33ae8a3..b025202 100644 --- a/server/src/wled_controller/static/js/features/dashboard.js +++ b/server/src/wled_controller/static/js/features/dashboard.js @@ -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; diff --git a/server/src/wled_controller/static/js/features/devices.js b/server/src/wled_controller/static/js/features/devices.js index f873892..0cbb6c7 100644 --- a/server/src/wled_controller/static/js/features/devices.js +++ b/server/src/wled_controller/static/js/features/devices.js @@ -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; diff --git a/server/src/wled_controller/static/js/features/kc-targets.js b/server/src/wled_controller/static/js/features/kc-targets.js index 11bfc20..077e230 100644 --- a/server/src/wled_controller/static/js/features/kc-targets.js +++ b/server/src/wled_controller/static/js/features/kc-targets.js @@ -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; diff --git a/server/src/wled_controller/static/js/features/pattern-templates.js b/server/src/wled_controller/static/js/features/pattern-templates.js index 6726d74..b887f7d 100644 --- a/server/src/wled_controller/static/js/features/pattern-templates.js +++ b/server/src/wled_controller/static/js/features/pattern-templates.js @@ -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; diff --git a/server/src/wled_controller/static/js/features/targets.js b/server/src/wled_controller/static/js/features/targets.js index 647729e..acede51 100644 --- a/server/src/wled_controller/static/js/features/targets.js +++ b/server/src/wled_controller/static/js/features/targets.js @@ -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'); } }); }