This commit is contained in:
Mateusz Gruszczyński
2026-09-01 11:10:28 +02:00
parent 3479ed750d
commit 9f08d7ccf9
30 changed files with 559 additions and 150 deletions
+41 -16
View File
@@ -73,29 +73,35 @@ document.addEventListener('click', async event => {
if (device && app.currentView !== 'devices' && deviceZoneDisabled(device.id) && ['power','temperature','mode','fan','toggle'].includes(action)) {
return toast(tr('devices.disabledZoneTechnicalOnly'), true);
}
if (action === 'power' && device) return sendDeviceCommand(device.id, {power:!device.power});
if (action === 'temperature' && device) return sendDeviceCommand(device.id, {target_temperature:clamp(Number(device.target_temperature)+Number(button.dataset.delta),8,30)});
if (action === 'power' && device) return sendDeviceCommand(device.id, current => ({power:!current?.power}));
if (action === 'temperature' && device) return sendDeviceCommand(device.id, current => ({target_temperature:clamp(Number(current?.target_temperature ?? device.target_temperature)+Number(button.dataset.delta),8,30)}));
if (action === 'mode' && device) return sendDeviceCommand(device.id, {mode:button.dataset.value, power:true});
if (action === 'fan' && device) return sendDeviceCommand(device.id, {fan_speed:Number(button.dataset.value)});
if (action === 'toggle' && device) return sendDeviceCommand(device.id, {[button.dataset.field]:!device[button.dataset.field]});
if (action === 'toggle' && device) return sendDeviceCommand(device.id, current => ({[button.dataset.field]:!current?.[button.dataset.field]}));
if (action === 'poll' && device) { try { button.disabled=true; updateDevice(await api(`/api/devices/${encodeURIComponent(device.id)}/poll`,{method:'POST'})); renderAll(); toast(tr('devices.readDone')); } catch(e){toast(e.message,true);} finally{button.disabled=false;} return; }
if (action === 'bind' && device) { try { button.disabled=true; updateDevice(await api(`/api/devices/${encodeURIComponent(device.id)}/bind`,{method:'POST'})); renderAll(); toast(tr('devices.bound')); } catch(e){toast(e.message,true);} finally{button.disabled=false;} return; }
if (action === 'rename-device' && device) return populateDeviceRename(device.id);
if (action === 'delete-device') return deleteEntity('devices', button.dataset.device, 'label.device');
if (action === 'house-mode') {
try { app.settings = await api('/api/house/control',{method:'POST',body:{mode:button.dataset.value}}); renderHouseClimate(); scheduleControlPlanLoad(); toast(tr('house.modeUpdated')); }
catch(error){ toast(error.message,true); } return;
try {
await enqueueClimateControlTask(async () => {
await api('/api/house/control',{method:'POST', body:{mode:button.dataset.value}});
await loadBootstrap();
});
toast(tr('house.modeUpdated'));
} catch(error){ toast(error.message,true); }
return;
}
if (action === 'house-power') {
const power = button.dataset.value === 'true';
if (!power && app.settings?.house_power_enabled !== false && !confirm(tr('house.powerOffConfirm'))) return;
try {
button.disabled = true;
const result = await api('/api/house/power',{method:'POST',body:{power}});
app.settings = result.settings || app.settings;
app.devices = result.devices || app.devices;
app.groups = result.groups || app.groups;
renderAll(); scheduleControlPlanLoad();
const result = await enqueueClimateControlTask(async () => {
const response = await api('/api/house/power',{method:'POST', body:{power}});
await loadBootstrap();
return response;
});
const failed = Array.isArray(result.failed) ? result.failed.length : 0;
if (failed) toast(tr('house.powerPartial', {count: failed}), true);
else toast(tr(power ? 'house.powerOnDone' : 'house.powerOffDone'));
@@ -105,20 +111,31 @@ document.addEventListener('click', async event => {
}
if (action === 'house-preset') {
try {
const result=await api('/api/house/preset',{method:'POST',body:{preset:button.dataset.value}});
app.settings=result.settings||app.settings; app.zones=result.zones||app.zones; app.devices=result.devices||app.devices;
renderAll(); scheduleControlPlanLoad();
const result = await enqueueClimateControlTask(async () => {
const response = await api('/api/house/preset',{method:'POST', body:{preset:button.dataset.value}});
await loadBootstrap();
return response;
});
const failed=Array.isArray(result.failed)?result.failed.length:0;
if(failed) toast(tr('house.powerPartial',{count:failed}),true); else toast(tr('house.presetUpdated'));
}
catch(error){ toast(error.message,true); } return;
catch(error){ toast(error.message,true); }
return;
}
if (action === 'group-power') return sendGroupControl(button.dataset.id,{power:button.dataset.value==='true'});
if (action === 'group-mode') return sendGroupControl(button.dataset.id,{mode:button.dataset.value});
if (action === 'group-preset') return sendGroupControl(button.dataset.id,{preset:button.dataset.value});
if (action === 'group-preset') { delete app.groupCustomDrafts[button.dataset.id]; return sendGroupControl(button.dataset.id,{preset:button.dataset.value}); }
if (action === 'group-custom-open') {
const editor=button.closest('.group-card')?.querySelector('[data-group-custom-editor]');
if(editor){ editor.hidden=false; const input=editor.querySelector('[data-group-custom-temperature]'); input?.focus(); input?.select(); }
const input=editor?.querySelector('[data-group-custom-temperature]');
const value=parseDecimal(input?.value);
app.groupCustomDrafts[button.dataset.id]={open:true,value:Number.isFinite(value)?value:23};
if(editor){ editor.hidden=false; input?.focus(); input?.select(); }
return;
}
if (action === 'group-custom-cancel') {
delete app.groupCustomDrafts[button.dataset.id];
renderGroups();
return;
}
if (action === 'group-custom-temperature') {
@@ -194,6 +211,14 @@ $('#themeSelect')?.addEventListener('change', event => setTheme(event.target.val
$('#logLevelFilter')?.addEventListener('change', loadLogs); $('#logCategoryFilter')?.addEventListener('change', loadLogs);
$('#settingsForm [name=notifications_provider]')?.addEventListener('change', updateNotificationFields);
$('#zoneForm [name=sensor_source]').addEventListener('change', updateZoneSensorFields);
document.addEventListener('input', event => {
const input=event.target.closest?.('[data-group-custom-temperature]');
if(!input) return;
const id=input.dataset.groupCustomTemperature;
if(!id) return;
app.groupCustomDrafts[id]={open:true,value:input.value};
});
document.addEventListener('keydown', event => {
const input=event.target.closest?.('[data-group-custom-temperature]');
if(!input || event.key!=='Enter') return;