diff --git a/src/static/patterns.js b/src/static/patterns.js index bd25e53..4a9daa1 100644 --- a/src/static/patterns.js +++ b/src/static/patterns.js @@ -237,6 +237,7 @@ document.addEventListener('DOMContentLoaded', () => { const norm = raw.endsWith('.py') ? raw.slice(0, -3).trim() : raw; try { const response = await fetch('/patterns/definitions', { + cache: 'no-store', headers: { Accept: 'application/json' }, }); if (!response.ok) { @@ -376,6 +377,7 @@ document.addEventListener('DOMContentLoaded', () => { try { const response = await fetch('/patterns', { + cache: 'no-store', headers: { Accept: 'application/json' }, }); if (!response.ok) { diff --git a/src/static/presets.js b/src/static/presets.js index 409eab7..9869ec0 100644 --- a/src/static/presets.js +++ b/src/static/presets.js @@ -720,6 +720,7 @@ document.addEventListener('DOMContentLoaded', () => { // Load pattern definitions from pattern.json let patternsPayload = null; let response = await fetch('/patterns/definitions', { + cache: 'no-store', headers: { Accept: 'application/json' }, }); if (response.ok) { @@ -730,6 +731,7 @@ document.addEventListener('DOMContentLoaded', () => { if (!Object.keys(normalized).length) { // Fallback when definitions route is unavailable or returns an empty map. response = await fetch('/patterns', { + cache: 'no-store', headers: { Accept: 'application/json' }, }); if (!response.ok) { @@ -1341,26 +1343,27 @@ document.addEventListener('DOMContentLoaded', () => { throw new Error('Failed to save preset'); } + // Same device targeting as Try: zone tab supplies names → /presets/push gets targets + select. + const section = document.querySelector('.presets-section[data-zone-id]'); + const deviceNames = tabDeviceNamesFromSection(section); + // Use saved preset from server response for sending const saved = await response.json().catch(() => null); if (saved && typeof saved === 'object') { if (currentEditId) { // PUT returns the preset object directly; use the existing ID - // Save & Send should not force-select the preset on devices. - await sendPresetViaEspNow(currentEditId, saved, [], true, false); + await sendPresetViaEspNow(currentEditId, saved, deviceNames, true, false); } else { // POST returns { id: preset } const entries = Object.entries(saved); if (entries.length > 0) { const [newId, presetData] = entries[0]; - // Save & Send should not force-select the preset on devices. - await sendPresetViaEspNow(newId, presetData, [], true, false); + await sendPresetViaEspNow(newId, presetData, deviceNames, true, false); } } } else { // Fallback: send what we just built - // Save & Send should not force-select the preset on devices. - await sendPresetViaEspNow(payload.name, payload, [], true, false); + await sendPresetViaEspNow(currentEditId || payload.name, payload, deviceNames, true, false); } await loadPresets(); diff --git a/src/static/style.css b/src/static/style.css index bc297a0..a7afa11 100644 --- a/src/static/style.css +++ b/src/static/style.css @@ -1253,24 +1253,32 @@ body.preset-ui-run .edit-mode-only { } /* Preset editor: brightness/delay field wrappers */ -.preset-editor-field { +#preset-editor-modal .preset-editor-field { flex: 1; + min-width: 10rem; display: flex; flex-direction: column; - align-items: flex-end; + align-items: stretch; } -.preset-editor-field label { +#preset-editor-modal .preset-editor-field label { align-self: stretch; } -.preset-editor-field input[type="number"] { - width: var(--n-input-width, 5ch); - max-width: 100%; +#preset-editor-modal .preset-editor-field input[type="number"] { + width: 100%; + min-width: 5.5rem; + max-width: 7rem; box-sizing: border-box; text-align: right; } +/* Preset editor n-parameter inputs need extra room for values + spinner controls. */ +#preset-editor-modal .n-input { + width: 6.5ch; + min-width: 5.5rem; +} + /* Pattern editor: numeric metadata row */ #pattern-editor-modal input[type="number"] { width: var(--n-input-width, 5ch);