feat(ui): add clear device presets action
Made-with: Cursor
This commit is contained in:
@@ -214,6 +214,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const presetsCloseButton = document.getElementById('presets-close-btn');
|
||||
const presetsList = document.getElementById('presets-list');
|
||||
const presetsAddButton = document.getElementById('preset-add-btn');
|
||||
const presetClearDeviceButton = document.getElementById('preset-clear-device-btn');
|
||||
const presetEditorModal = document.getElementById('preset-editor-modal');
|
||||
const presetEditorCloseButton = document.getElementById('preset-editor-close-btn');
|
||||
const presetNameInput = document.getElementById('preset-name-input');
|
||||
@@ -283,7 +284,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (!input) {
|
||||
return 0;
|
||||
}
|
||||
return parseInt(input.value, 10) || 0;
|
||||
const n = parseInt(String(input.value).trim(), 10);
|
||||
return Number.isFinite(n) ? n : 0;
|
||||
};
|
||||
|
||||
const renderPresetColors = (colors, paletteRefs) => {
|
||||
@@ -564,14 +566,18 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
const nKey = `n${i}`;
|
||||
const inputEl = document.getElementById(`preset-${nKey}-input`);
|
||||
if (inputEl) {
|
||||
if (preset[nKey] !== undefined) {
|
||||
inputEl.value = preset[nKey] || 0;
|
||||
if (preset[nKey] !== undefined && preset[nKey] !== null) {
|
||||
const raw = preset[nKey];
|
||||
const n = typeof raw === 'number' ? raw : parseInt(String(raw), 10);
|
||||
inputEl.value = String(Number.isFinite(n) ? n : 0);
|
||||
} else {
|
||||
const label = nToLabel[nKey];
|
||||
if (label && preset[label] !== undefined) {
|
||||
inputEl.value = preset[label] || 0;
|
||||
if (label && preset[label] !== undefined && preset[label] !== null) {
|
||||
const rawL = preset[label];
|
||||
const nL = typeof rawL === 'number' ? rawL : parseInt(String(rawL), 10);
|
||||
inputEl.value = String(Number.isFinite(nL) ? nL : 0);
|
||||
} else {
|
||||
inputEl.value = 0;
|
||||
inputEl.value = '0';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -811,6 +817,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
});
|
||||
}
|
||||
|
||||
const hasPatternMeta =
|
||||
patternConfig && typeof patternConfig === 'object' && Object.keys(patternConfig).length > 0;
|
||||
const hasAnyNLabel = visibleNKeys.size > 0;
|
||||
|
||||
for (let i = 1; i <= 8; i++) {
|
||||
const nKey = `n${i}`;
|
||||
const labelEl = document.getElementById(`preset-${nKey}-label`);
|
||||
@@ -824,7 +834,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
if (groupEl) {
|
||||
groupEl.style.display = show ? '' : 'none';
|
||||
}
|
||||
if (inputEl && !show) {
|
||||
// Only clear hidden n inputs when we know this pattern's metadata (avoids wiping n3..n4
|
||||
// while definitions are still loading, or when twinkle exists only as a driver file).
|
||||
if (inputEl && !show && (hasAnyNLabel || hasPatternMeta)) {
|
||||
inputEl.value = '0';
|
||||
}
|
||||
}
|
||||
@@ -969,6 +981,30 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
openEditor();
|
||||
});
|
||||
}
|
||||
if (presetClearDeviceButton) {
|
||||
presetClearDeviceButton.addEventListener('click', async () => {
|
||||
const section = document.querySelector('.presets-section[data-zone-id]');
|
||||
const deviceNames = tabDeviceNamesFromSection(section);
|
||||
if (!deviceNames.length) {
|
||||
alert('No devices found in the current zone.');
|
||||
return;
|
||||
}
|
||||
if (!window.confirm('Clear all presets on current zone devices?')) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const targetMacs =
|
||||
typeof window.tabsManager !== 'undefined' &&
|
||||
typeof window.tabsManager.resolveTabDeviceMacs === 'function'
|
||||
? await window.tabsManager.resolveTabDeviceMacs(deviceNames)
|
||||
: [];
|
||||
await postDriverSequence([{ v: '1', clear_presets: true, save: true }], targetMacs);
|
||||
} catch (error) {
|
||||
console.error('Clear device presets failed:', error);
|
||||
alert('Failed to clear presets on devices.');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const showAddPresetToTabModal = async (optionalTabId) => {
|
||||
let zoneId = optionalTabId;
|
||||
@@ -1405,6 +1441,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
clearForm();
|
||||
});
|
||||
|
||||
const coercePresetInt = (v, def = 0) => {
|
||||
if (typeof v === 'number' && Number.isFinite(v)) {
|
||||
return v;
|
||||
}
|
||||
const t = parseInt(String(v), 10);
|
||||
return Number.isFinite(t) ? t : def;
|
||||
};
|
||||
|
||||
// Build driver messages for a single preset; deliver via /presets/push (ESP-NOW + TCP).
|
||||
// Send order:
|
||||
// 1) preset payload (optionally with save)
|
||||
@@ -1429,12 +1473,12 @@ const sendPresetViaEspNow = async (presetId, preset, deviceNames, saveToDevice =
|
||||
? preset.brightness
|
||||
: (typeof preset.br === 'number' ? preset.br : 127),
|
||||
auto: typeof preset.auto === 'boolean' ? preset.auto : true,
|
||||
n1: typeof preset.n1 === 'number' ? preset.n1 : 0,
|
||||
n2: typeof preset.n2 === 'number' ? preset.n2 : 0,
|
||||
n3: typeof preset.n3 === 'number' ? preset.n3 : 0,
|
||||
n4: typeof preset.n4 === 'number' ? preset.n4 : 0,
|
||||
n5: typeof preset.n5 === 'number' ? preset.n5 : 0,
|
||||
n6: typeof preset.n6 === 'number' ? preset.n6 : 0,
|
||||
n1: coercePresetInt(preset.n1),
|
||||
n2: coercePresetInt(preset.n2),
|
||||
n3: coercePresetInt(preset.n3),
|
||||
n4: coercePresetInt(preset.n4),
|
||||
n5: coercePresetInt(preset.n5),
|
||||
n6: coercePresetInt(preset.n6),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -160,6 +160,7 @@
|
||||
<h2>Presets</h2>
|
||||
<div class="modal-actions">
|
||||
<button class="btn btn-primary" id="preset-add-btn">Add</button>
|
||||
<button class="btn btn-danger" id="preset-clear-device-btn">Clear Device Presets</button>
|
||||
</div>
|
||||
<div id="presets-list" class="profiles-list"></div>
|
||||
<div class="modal-actions">
|
||||
|
||||
Reference in New Issue
Block a user