This commit is contained in:
Mateusz Gruszczyński
2026-09-14 23:10:17 +02:00
parent 4bb9c8621a
commit 0a2fb8c6c7
47 changed files with 1337 additions and 372 deletions
+79 -13
View File
@@ -85,6 +85,19 @@ document.addEventListener('click', async event => {
finally { button.disabled = false; }
return;
}
if (action === 'edit-device-group') { await openDeviceGroupsDialog(button.dataset.id || ''); return; }
if (action === 'delete-device-group') {
const group = (app.deviceGroups || []).find(item => item.id === button.dataset.id);
if (!group || !confirm(`${tr('actions.delete')} ${group.name}?`)) return;
try {
await api(`/api/device-groups/${encodeURIComponent(group.id)}`, { method: 'DELETE' });
await loadBootstrap();
renderDeviceGroupsDialogList();
await populateDeviceGroupForm(null);
toast(tr('devices.installationDeleted'));
} catch (error) { toast(error.message, true); }
return;
}
const device = app.devices.find(v => v.id === button.dataset.device);
if (action === 'open-ping' && device) { openDevicePing(device.id); return; }
if (action === 'ping-toggle') { if (app.pingMonitor.running) stopPingMonitor(); else startPingMonitor(); return; }
@@ -361,7 +374,7 @@ $('#renameDeviceForm').addEventListener('submit', async event => {
if (isCloud) {
const check = await api('/api/integrations/gree-cloud/test', { method: 'POST' });
if (!check.ok) throw new Error(check.message || check.status || tr('settings.cloudConnectionFailed'));
if (result) { result.hidden = false; result.classList.add('success'); result.textContent = tr('settings.cloudConnected', { count: Number(check.device_count || 0) }); }
if (result) { const message = tr('settings.cloudConnected', { count: Number(check.device_count || 0) }); result.hidden = false; result.classList.add('success'); result.innerHTML = `<span>${esc(tr('status.online'))}</span><strong>${esc(message)}</strong>`; }
markFormClean(form); renderAll(); toast(tr('devices.savedAndChecked')); return;
}
const protocolChanged = previous && Number(previous.protocol_version) !== Number(raw.protocol_version);
@@ -380,7 +393,8 @@ $('#renameDeviceForm').addEventListener('submit', async event => {
}
if (result) {
result.hidden = false; result.classList.add('success');
result.textContent = tr('devices.connectionCheckOk', { ms: Math.round(Number(probe.response_time_ms || 0)) });
const message = tr('devices.connectionCheckOk', { ms: Math.round(Number(probe.response_time_ms || 0)) });
result.innerHTML = `<span>${esc(tr('status.online'))}</span><strong>${esc(message)}</strong>`;
}
markFormClean(form);
renderAll();
@@ -388,7 +402,8 @@ $('#renameDeviceForm').addEventListener('submit', async event => {
} catch (error) {
if (result) {
result.hidden = false; result.classList.add('error');
result.textContent = tr('devices.connectionCheckFailed', { error: error.message || String(error) });
const message = tr('devices.connectionCheckFailed', { error: error.message || String(error) });
result.innerHTML = `<span>${esc(tr('devices.lastError'))}</span><strong>${esc(message)}</strong>`;
}
markFormClean(form);
renderAll();
@@ -401,17 +416,22 @@ $('#deviceDetailsForm')?.addEventListener('submit', async event => {
event.preventDefault();
const form = event.currentTarget;
const raw = Object.fromEntries(new FormData(form));
const option = form.ha_energy_entity_id.selectedOptions?.[0];
const patch = {
name: raw.name.trim(),
energy_source: raw.energy_source || 'auto',
ha_energy_entity_id: raw.ha_energy_entity_id || null,
ha_energy_unit: option?.value ? (option.dataset.unit || null) : null,
ha_energy_device_class: option?.value ? (option.dataset.deviceClass || null) : null,
ha_energy_state_class: option?.value ? (option.dataset.stateClass || null) : null,
};
const deviceId = form.elements.id.value;
const installation = deviceInstallationForDevice(deviceId);
const groupOwnsEnergy = !!installation && (!!installation.energy_device_id || !!installation.ha_energy_entity_id);
const patch = { name: String(raw.name || '').trim() };
if (!groupOwnsEnergy) {
const option = form.ha_energy_entity_id.selectedOptions?.[0];
Object.assign(patch, {
energy_source: raw.energy_source || 'auto',
ha_energy_entity_id: raw.ha_energy_entity_id || null,
ha_energy_unit: option?.value ? (option.dataset.unit || null) : null,
ha_energy_device_class: option?.value ? (option.dataset.deviceClass || null) : null,
ha_energy_state_class: option?.value ? (option.dataset.stateClass || null) : null,
});
}
await runFormTask(form, async () => {
const device = await api(`/api/devices/${encodeURIComponent(raw.id)}`, { method: 'PATCH', body: patch });
const device = await api(`/api/devices/${encodeURIComponent(deviceId)}`, { method: 'PATCH', body: patch });
updateDevice(device);
form.closest('dialog').close();
renderAll();
@@ -421,6 +441,52 @@ $('#deviceDetailsForm')?.addEventListener('submit', async event => {
$('#deviceDetailsForm')?.ha_energy_entity_id?.addEventListener('change', updateDeviceEnergySensorMeta);
$('#deviceGroupsButton')?.addEventListener('click', () => openDeviceGroupsDialog());
$('#deviceGroupNew')?.addEventListener('click', () => populateDeviceGroupForm(null));
$('#deviceGroupForm')?.addEventListener('change', event => {
const form = event.currentTarget;
if (event.target.name === 'kind' && form.kind.value === 'split') {
const checked = $$('#deviceGroupDeviceChoices input[name="device_ids"]:checked');
checked.slice(1).forEach(input => { input.checked = false; });
syncDeviceGroupMemberSelects();
}
if (event.target.name === 'device_ids') {
if (form.kind.value === 'split' && event.target.checked) {
$$('#deviceGroupDeviceChoices input[name="device_ids"]:checked').forEach(input => { if (input !== event.target) input.checked = false; });
}
syncDeviceGroupMemberSelects();
}
if (event.target.name === 'ha_energy_entity_id') updateDeviceGroupEnergySensorMeta();
});
$('#deviceGroupForm')?.addEventListener('submit', async event => {
event.preventDefault();
const form = event.currentTarget;
const ids = selectedDeviceGroupIds();
if (!ids.length) return showFormError(form, tr('energy.selectAtLeastOne'));
const option = form.ha_energy_entity_id.selectedOptions?.[0];
const body = {
name: form.name.value.trim(),
kind: form.kind.value || 'split',
device_ids: ids,
energy_source: form.energy_source.value || 'auto',
energy_device_id: form.energy_device_id.value || null,
ha_energy_entity_id: form.ha_energy_entity_id.value || null,
ha_energy_unit: option?.value ? (option.dataset.unit || null) : null,
ha_energy_device_class: option?.value ? (option.dataset.deviceClass || null) : null,
ha_energy_state_class: option?.value ? (option.dataset.stateClass || null) : null,
outdoor_temperature_device_id: form.outdoor_temperature_device_id.value || null,
};
const id = form.elements.id.value;
await runFormTask(form, async () => {
await api(id ? `/api/device-groups/${encodeURIComponent(id)}` : '/api/device-groups', { method: id ? 'PUT' : 'POST', body });
await loadBootstrap();
renderDeviceGroupsDialogList();
await populateDeviceGroupForm(null);
toast(tr('devices.installationSaved'));
});
});
$('#cloudDiagnosticsRefresh')?.addEventListener('click', () => {
const id = $('#cloudDiagnosticsDialog')?.dataset.deviceId;
if (id) openCloudDiagnostics(id);