diff --git a/server/src/wled_controller/static/js/core/command-palette.js b/server/src/wled_controller/static/js/core/command-palette.js index bb0e164..125f849 100644 --- a/server/src/wled_controller/static/js/core/command-palette.js +++ b/server/src/wled_controller/static/js/core/command-palette.js @@ -61,8 +61,8 @@ function _buildItems(results, states = {}) { name: tgt.name, detail: t('search.action.stop'), group: 'actions', icon: '■', action: async () => { const resp = await fetchWithAuth(`/output-targets/${tgt.id}/stop`, { method: 'POST' }); - if (resp.ok) showToast(t('device.stopped'), 'success'); - else showToast(t('target.error.stop_failed'), 'error'); + if (resp.ok) { showToast(t('device.stopped'), 'success'); } + else { const err = await resp.json().catch(() => ({})); const d = err.detail || err.message || ''; const ds = Array.isArray(d) ? d.map(x => x.msg || x).join('; ') : String(d); showToast(ds || t('target.error.stop_failed'), 'error'); } }, }); } else { @@ -70,8 +70,8 @@ function _buildItems(results, states = {}) { name: tgt.name, detail: t('search.action.start'), group: 'actions', icon: '▶', action: async () => { const resp = await fetchWithAuth(`/output-targets/${tgt.id}/start`, { method: 'POST' }); - if (resp.ok) showToast(t('device.started'), 'success'); - else showToast(t('target.error.start_failed'), 'error'); + if (resp.ok) { showToast(t('device.started'), 'success'); } + else { const err = await resp.json().catch(() => ({})); const d = err.detail || err.message || ''; const ds = Array.isArray(d) ? d.map(x => x.msg || x).join('; ') : String(d); showToast(ds || t('target.error.start_failed'), 'error'); } }, }); } @@ -92,8 +92,8 @@ function _buildItems(results, states = {}) { name: a.name, detail: t('search.action.disable'), group: 'actions', icon: ICON_AUTOMATION, action: async () => { const resp = await fetchWithAuth(`/automations/${a.id}/disable`, { method: 'POST' }); - if (resp.ok) showToast(t('search.action.disable') + ': ' + a.name, 'success'); - else showToast(t('search.action.disable') + ' failed', 'error'); + if (resp.ok) { showToast(t('search.action.disable') + ': ' + a.name, 'success'); } + else { const err = await resp.json().catch(() => ({})); const d = err.detail || err.message || ''; const ds = Array.isArray(d) ? d.map(x => x.msg || x).join('; ') : String(d); showToast(ds || (t('search.action.disable') + ' failed'), 'error'); } }, }); } else { @@ -101,8 +101,8 @@ function _buildItems(results, states = {}) { name: a.name, detail: t('search.action.enable'), group: 'actions', icon: ICON_AUTOMATION, action: async () => { const resp = await fetchWithAuth(`/automations/${a.id}/enable`, { method: 'POST' }); - if (resp.ok) showToast(t('search.action.enable') + ': ' + a.name, 'success'); - else showToast(t('search.action.enable') + ' failed', 'error'); + if (resp.ok) { showToast(t('search.action.enable') + ': ' + a.name, 'success'); } + else { const err = await resp.json().catch(() => ({})); const d = err.detail || err.message || ''; const ds = Array.isArray(d) ? d.map(x => x.msg || x).join('; ') : String(d); showToast(ds || (t('search.action.enable') + ' failed'), 'error'); } }, }); } @@ -153,8 +153,8 @@ function _buildItems(results, states = {}) { name: sp.name, detail: t('search.action.activate'), group: 'actions', icon: '⚡', action: async () => { const resp = await fetchWithAuth(`/scene-presets/${sp.id}/activate`, { method: 'POST' }); - if (resp.ok) showToast(t('scenes.activated'), 'success'); - else showToast(t('scenes.error.activate_failed'), 'error'); + if (resp.ok) { showToast(t('scenes.activated'), 'success'); } + else { const err = await resp.json().catch(() => ({})); const d = err.detail || err.message || ''; const ds = Array.isArray(d) ? d.map(x => x.msg || x).join('; ') : String(d); showToast(ds || t('scenes.error.activate_failed'), 'error'); } }, }); }); diff --git a/server/src/wled_controller/static/js/features/advanced-calibration.js b/server/src/wled_controller/static/js/features/advanced-calibration.js index 53d7d66..2633dcd 100644 --- a/server/src/wled_controller/static/js/features/advanced-calibration.js +++ b/server/src/wled_controller/static/js/features/advanced-calibration.js @@ -172,11 +172,13 @@ export async function saveAdvancedCalibration() { _modal.forceClose(); } else { const err = await resp.json().catch(() => ({})); - showToast(err.message || t('calibration.error.save_failed'), 'error'); + const detail = err.detail || err.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + showToast(detailStr || t('calibration.error.save_failed'), 'error'); } } catch (error) { if (error.isAuth) return; - showToast(t('calibration.error.save_failed'), 'error'); + showToast(error.message || t('calibration.error.save_failed'), 'error'); } } diff --git a/server/src/wled_controller/static/js/features/automations.js b/server/src/wled_controller/static/js/features/automations.js index d61c240..ecd5d89 100644 --- a/server/src/wled_controller/static/js/features/automations.js +++ b/server/src/wled_controller/static/js/features/automations.js @@ -721,7 +721,10 @@ export async function toggleAutomationEnabled(automationId, enable) { const resp = await fetchWithAuth(`/automations/${automationId}/${action}`, { method: 'POST', }); - if (!resp.ok) throw new Error(`Failed to ${action} automation`); + if (!resp.ok) { + const err = await resp.json().catch(() => ({})); + throw new Error(err.detail || `Failed to ${action} automation`); + } automationsCacheObj.invalidate(); loadAutomations(); } catch (e) { @@ -768,7 +771,10 @@ export async function deleteAutomation(automationId, automationName) { const resp = await fetchWithAuth(`/automations/${automationId}`, { method: 'DELETE', }); - if (!resp.ok) throw new Error('Failed to delete automation'); + if (!resp.ok) { + const err = await resp.json().catch(() => ({})); + throw new Error(err.detail || 'Failed to delete automation'); + } showToast(t('automations.deleted'), 'success'); automationsCacheObj.invalidate(); loadAutomations(); diff --git a/server/src/wled_controller/static/js/features/calibration.js b/server/src/wled_controller/static/js/features/calibration.js index 08d99ee..75a23a3 100644 --- a/server/src/wled_controller/static/js/features/calibration.js +++ b/server/src/wled_controller/static/js/features/calibration.js @@ -815,13 +815,15 @@ export async function toggleTestEdge(edge) { }); if (!response.ok) { const errorData = await response.json(); - error.textContent = t('calibration.error.test_toggle_failed'); + const detail = errorData.detail || errorData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + error.textContent = detailStr || t('calibration.error.test_toggle_failed'); error.style.display = 'block'; } } catch (err) { if (err.isAuth) return; console.error('Failed to toggle CSS test edge:', err); - error.textContent = t('calibration.error.test_toggle_failed'); + error.textContent = err.message || t('calibration.error.test_toggle_failed'); error.style.display = 'block'; } return; @@ -845,13 +847,15 @@ export async function toggleTestEdge(edge) { }); if (!response.ok) { const errorData = await response.json(); - error.textContent = t('calibration.error.test_toggle_failed'); + const detail = errorData.detail || errorData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + error.textContent = detailStr || t('calibration.error.test_toggle_failed'); error.style.display = 'block'; } } catch (err) { if (err.isAuth) return; console.error('Failed to toggle test edge:', err); - error.textContent = t('calibration.error.test_toggle_failed'); + error.textContent = err.message || t('calibration.error.test_toggle_failed'); error.style.display = 'block'; } } @@ -948,13 +952,15 @@ export async function saveCalibration() { } } else { const errorData = await response.json(); - error.textContent = t('calibration.error.save_failed'); + const detail = errorData.detail || errorData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + error.textContent = detailStr || t('calibration.error.save_failed'); error.style.display = 'block'; } } catch (err) { if (err.isAuth) return; console.error('Failed to save calibration:', err); - error.textContent = t('calibration.error.save_failed'); + error.textContent = err.message || t('calibration.error.save_failed'); error.style.display = 'block'; } } diff --git a/server/src/wled_controller/static/js/features/device-discovery.js b/server/src/wled_controller/static/js/features/device-discovery.js index a1e0f80..533f7f8 100644 --- a/server/src/wled_controller/static/js/features/device-discovery.js +++ b/server/src/wled_controller/static/js/features/device-discovery.js @@ -871,13 +871,15 @@ export async function handleAddDevice(event) { } else { const errorData = await response.json(); console.error('Failed to add device:', errorData); - error.textContent = t('device_discovery.error.add_failed'); + const detail = errorData.detail || errorData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + error.textContent = detailStr || t('device_discovery.error.add_failed'); error.style.display = 'block'; } } catch (err) { if (err.isAuth) return; console.error('Failed to add device:', err); - showToast(t('device_discovery.error.add_failed'), 'error'); + showToast(err.message || t('device_discovery.error.add_failed'), 'error'); } } diff --git a/server/src/wled_controller/static/js/features/devices.js b/server/src/wled_controller/static/js/features/devices.js index 4d8e07f..cc75709 100644 --- a/server/src/wled_controller/static/js/features/devices.js +++ b/server/src/wled_controller/static/js/features/devices.js @@ -516,7 +516,9 @@ export async function saveDeviceSettings() { if (!deviceResponse.ok) { const errorData = await deviceResponse.json(); - settingsModal.showError(t('device.error.update')); + const detail = errorData.detail || errorData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + settingsModal.showError(detailStr || t('device.error.update')); return; } @@ -527,7 +529,7 @@ export async function saveDeviceSettings() { } catch (err) { if (err.isAuth) return; console.error('Failed to save device settings:', err); - settingsModal.showError(t('device.error.save')); + settingsModal.showError(err.message || t('device.error.save')); } } @@ -546,11 +548,14 @@ export async function saveCardBrightness(deviceId, value) { body: JSON.stringify({ brightness: bri }) }); if (!resp.ok) { - showToast(t('device.error.brightness'), 'error'); + const errData = await resp.json().catch(() => ({})); + const detail = errData.detail || errData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + showToast(detailStr || t('device.error.brightness'), 'error'); } } catch (err) { if (err.isAuth) return; - showToast(t('device.error.brightness'), 'error'); + showToast(err.message || t('device.error.brightness'), 'error'); } } diff --git a/server/src/wled_controller/static/js/features/scene-presets.js b/server/src/wled_controller/static/js/features/scene-presets.js index ef54796..5bc1fee 100644 --- a/server/src/wled_controller/static/js/features/scene-presets.js +++ b/server/src/wled_controller/static/js/features/scene-presets.js @@ -319,7 +319,10 @@ export async function activateScenePreset(presetId) { method: 'POST', }); if (!resp.ok) { - showToast(t('scenes.error.activate_failed'), 'error'); + const errData = await resp.json().catch(() => ({})); + const detail = errData.detail || errData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + showToast(detailStr || t('scenes.error.activate_failed'), 'error'); return; } const result = await resp.json(); @@ -352,11 +355,14 @@ export async function recaptureScenePreset(presetId) { scenePresetsCache.invalidate(); _reloadScenesTab(); } else { - showToast(t('scenes.error.recapture_failed'), 'error'); + const errData = await resp.json().catch(() => ({})); + const detail = errData.detail || errData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + showToast(detailStr || t('scenes.error.recapture_failed'), 'error'); } } catch (error) { if (error.isAuth) return; - showToast(t('scenes.error.recapture_failed'), 'error'); + showToast(error.message || t('scenes.error.recapture_failed'), 'error'); } } @@ -425,11 +431,14 @@ export async function deleteScenePreset(presetId) { scenePresetsCache.invalidate(); _reloadScenesTab(); } else { - showToast(t('scenes.error.delete_failed'), 'error'); + const errData = await resp.json().catch(() => ({})); + const detail = errData.detail || errData.message || ''; + const detailStr = Array.isArray(detail) ? detail.map(d => d.msg || d).join('; ') : String(detail); + showToast(detailStr || t('scenes.error.delete_failed'), 'error'); } } catch (error) { if (error.isAuth) return; - showToast(t('scenes.error.delete_failed'), 'error'); + showToast(error.message || t('scenes.error.delete_failed'), 'error'); } }