v0.9.7
This commit is contained in:
@@ -14,6 +14,7 @@ function knownHaEntities() {
|
||||
...app.zones.map(zone => zone.ha_entity_id).filter(Boolean),
|
||||
app.settings?.home_assistant?.default_entity_id,
|
||||
app.settings?.home_assistant?.outdoor_entity_id,
|
||||
...(app.flowSharedInputs || []).map(item => item?.config?.entity_id).filter(Boolean),
|
||||
...app.historyData.sensors.map(row => row.entity_id),
|
||||
].filter(Boolean))].sort();
|
||||
}
|
||||
@@ -24,6 +25,89 @@ function renderSensorAliases() {
|
||||
host.innerHTML = entities.length ? entities.map(entity => `<div class="sensor-alias-row"><span class="mono" title="${esc(entity)}">${esc(entity)}</span><input data-sensor-alias="${esc(entity)}" value="${esc(app.sensorAliases?.[entity] || '')}" placeholder="${esc(tr('settings.aliasPlaceholder'))}"><button type="button" class="sensor-alias-clear" data-clear-sensor-alias="${esc(entity)}" title="${esc(tr('actions.clear'))}">×</button></div>`).join('') : `<div class="empty compact">${esc(tr('settings.noSensorAliases'))}</div>`;
|
||||
}
|
||||
|
||||
function flowSharedInputKinds() {
|
||||
return [
|
||||
['constant', 'flow.node.constant'], ['ha_state', 'flow.node.haState'], ['ha_numeric', 'flow.node.haNumeric'],
|
||||
['ha_attribute', 'flow.node.haAttribute'], ['ha_available', 'flow.node.haAvailable'],
|
||||
['outdoor_temperature', 'flow.node.outdoorTemperature'], ['device_temperature', 'flow.node.deviceTemperature'],
|
||||
['zone_temperature', 'flow.node.zoneTemperature'], ['house_mode', 'flow.node.houseMode'],
|
||||
['device_state', 'flow.node.deviceState'], ['zone_state', 'flow.node.zoneState'],
|
||||
['group_state', 'flow.node.groupState'], ['night_mode', 'flow.node.nightMode'],
|
||||
];
|
||||
}
|
||||
|
||||
function sharedFlowInputSummary(item) {
|
||||
if (!item) return '—';
|
||||
try { return flowNodeSummary({ kind: item.kind, config: item.config || {} }); } catch (_) { return item.kind || '—'; }
|
||||
}
|
||||
|
||||
function renderFlowSharedInputs() {
|
||||
const host = $('#flowSharedInputList'); if (!host) return;
|
||||
const items = app.flowSharedInputs || [];
|
||||
host.innerHTML = items.length ? items.map(item => `<div class="flow-shared-input-row">
|
||||
<div><strong>${esc(item.name)}</strong><small>${esc(flowNodeTitle(FLOW_NODE_META[item.kind] || { title:item.kind }))} · ${esc(sharedFlowInputSummary(item))}</small><code>${esc(item.id)}</code></div>
|
||||
<div class="flow-shared-input-actions"><button type="button" class="secondary" data-flow-shared-edit="${esc(item.id)}">${esc(tr('actions.edit'))}</button><button type="button" class="danger" data-flow-shared-delete="${esc(item.id)}">${esc(tr('actions.delete'))}</button></div>
|
||||
</div>`).join('') : `<div class="empty compact"><strong>${esc(tr('flow.sharedInputsEmpty'))}</strong><span>${esc(tr('flow.sharedInputsEmptyHint'))}</span></div>`;
|
||||
const revision = $('#flowSharedInputsRevision');
|
||||
if (revision) revision.value = JSON.stringify(items);
|
||||
}
|
||||
|
||||
function sharedFlowOptions(items, selected, label = item => item.name) {
|
||||
return items.map(item => `<option value="${esc(item.id)}" ${item.id === selected ? 'selected' : ''}>${esc(label(item))}</option>`).join('');
|
||||
}
|
||||
|
||||
function sharedFlowOperatorOptions(selected = 'eq') {
|
||||
return [['lt','<'],['lte','≤'],['gt','>'],['gte','≥'],['eq','='],['neq','≠']].map(([value,label]) => `<option value="${value}" ${value === selected ? 'selected' : ''}>${label}</option>`).join('');
|
||||
}
|
||||
|
||||
function renderFlowSharedInputFields(kind, config = {}) {
|
||||
const host = $('#flowSharedInputFields'); if (!host) return;
|
||||
const c = config || {};
|
||||
const comparison = (temperature = false) => `<div class="two"><label><span>${esc(tr('flow.operator'))}</span><select data-shared-config="operator">${sharedFlowOperatorOptions(c.operator || 'lt')}</select></label><label><span>${esc(temperature ? tr('automations.thresholdC') : tr('flow.value'))}</span><input type="number" step="0.1" data-shared-config="value" value="${Number(c.value ?? 0)}"></label></div>`;
|
||||
const textComparison = () => `<div class="two"><label><span>${esc(tr('flow.operator'))}</span><select data-shared-config="operator"><option value="eq" ${c.operator !== 'neq' ? 'selected' : ''}>=</option><option value="neq" ${c.operator === 'neq' ? 'selected' : ''}>≠</option></select></label><label><span>${esc(tr('flow.value'))}</span><input data-shared-config="value" value="${esc(c.value ?? '')}"></label></div>`;
|
||||
let fields = '';
|
||||
if (kind === 'constant') fields = `<label><span>${esc(tr('flow.value'))}</span><select data-shared-config="value"><option value="true" ${c.value !== false ? 'selected' : ''}>${esc(tr('common.yes'))}</option><option value="false" ${c.value === false ? 'selected' : ''}>${esc(tr('common.no'))}</option></select></label>`;
|
||||
else if (kind === 'ha_state') fields = `<label><span>entity_id</span><input data-shared-config="entity_id" value="${esc(c.entity_id || '')}" placeholder="binary_sensor.window"></label>${textComparison()}`;
|
||||
else if (kind === 'ha_numeric') fields = `<label><span>entity_id</span><input data-shared-config="entity_id" value="${esc(c.entity_id || '')}" placeholder="sensor.energy_price"></label>${comparison(false)}`;
|
||||
else if (kind === 'ha_attribute') fields = `<label><span>entity_id</span><input data-shared-config="entity_id" value="${esc(c.entity_id || '')}" placeholder="climate.living_room"></label><label><span>${esc(tr('flow.attribute'))}</span><input data-shared-config="attribute" value="${esc(c.attribute || '')}" placeholder="hvac_action"></label><div class="two"><label><span>${esc(tr('flow.operator'))}</span><select data-shared-config="operator">${sharedFlowOperatorOptions(c.operator || 'eq')}</select></label><label><span>${esc(tr('flow.value'))}</span><input data-shared-config="value" value="${esc(c.value ?? '')}"></label></div>`;
|
||||
else if (kind === 'ha_available') fields = `<label><span>entity_id</span><input data-shared-config="entity_id" value="${esc(c.entity_id || '')}" placeholder="binary_sensor.window"></label><p class="field-note">${esc(tr('flow.haAvailableHint'))}</p>`;
|
||||
else if (kind === 'outdoor_temperature') fields = comparison(true);
|
||||
else if (kind === 'device_temperature') fields = `<label><span>${esc(tr('common.device'))}</span><select data-shared-config="device_id">${sharedFlowOptions(app.devices, c.device_id)}</select></label>${comparison(true)}`;
|
||||
else if (kind === 'zone_temperature') fields = `<label><span>${esc(tr('common.zone'))}</span><select data-shared-config="zone_id">${sharedFlowOptions(app.zones, c.zone_id)}</select></label>${comparison(true)}`;
|
||||
else if (kind === 'house_mode') fields = `<div class="two"><label><span>${esc(tr('flow.operator'))}</span><select data-shared-config="operator"><option value="eq" ${c.operator !== 'neq' ? 'selected' : ''}>=</option><option value="neq" ${c.operator === 'neq' ? 'selected' : ''}>≠</option></select></label><label><span>${esc(tr('flow.houseMode'))}</span><select data-shared-config="value">${['cool','heat','off'].map(v => `<option value="${v}" ${c.value === v ? 'selected' : ''}>${esc(v === 'off' ? tr('common.off') : tr(`mode.${v}`))}</option>`).join('')}</select></label></div>`;
|
||||
else if (kind === 'device_state') fields = `<label><span>${esc(tr('common.device'))}</span><select data-shared-config="device_id">${sharedFlowOptions(app.devices, c.device_id)}</select></label><label><span>${esc(tr('flow.field'))}</span><select data-shared-config="field">${['enabled','online','power','mode','fan_speed','swing_vertical','swing_horizontal','quiet','turbo','light','air','xfan','health','sleep'].map(v => `<option value="${v}" ${c.field === v ? 'selected' : ''}>${esc(v)}</option>`).join('')}</select></label>${textComparison()}`;
|
||||
else if (kind === 'zone_state') fields = `<label><span>${esc(tr('common.zone'))}</span><select data-shared-config="zone_id">${sharedFlowOptions(app.zones, c.zone_id)}</select></label><label><span>${esc(tr('flow.field'))}</span><select data-shared-config="field">${['enabled','mode','active_preset','demand','control_owner','device_manual_override','local_thermostat_power'].map(v => `<option value="${v}" ${c.field === v ? 'selected' : ''}>${esc(v)}</option>`).join('')}</select></label>${textComparison()}`;
|
||||
else if (kind === 'group_state') fields = `<label><span>${esc(tr('groups.group'))}</span><select data-shared-config="group_id">${sharedFlowOptions(app.groups, c.group_id)}</select></label><input type="hidden" data-shared-config="field" value="power_enabled">${textComparison()}`;
|
||||
else if (kind === 'night_mode') fields = `<p class="field-note">${esc(tr('flow.nightModeHint'))}</p>`;
|
||||
host.innerHTML = fields;
|
||||
}
|
||||
|
||||
function openFlowSharedInputEditor(id = '') {
|
||||
const form = $('#flowSharedInputForm'), dialog = $('#flowSharedInputDialog'); if (!form || !dialog) return;
|
||||
const item = id ? (app.flowSharedInputs || []).find(value => value.id === id) : null;
|
||||
const kindSelect = form.kind;
|
||||
kindSelect.innerHTML = flowSharedInputKinds().map(([kind,key]) => `<option value="${kind}">${esc(tr(key))}</option>`).join('');
|
||||
form.id.value = item?.id || '';
|
||||
form.name.value = item?.name || '';
|
||||
form.kind.value = item?.kind || 'constant';
|
||||
form.dataset.editingId = item?.id || '';
|
||||
renderFlowSharedInputFields(form.kind.value, item?.config || flowDefaultConfig(form.kind.value));
|
||||
dialog.showModal();
|
||||
setTimeout(() => form.name.focus(), 0);
|
||||
}
|
||||
|
||||
function collectFlowSharedInputConfig(kind) {
|
||||
const config = {};
|
||||
$$('[data-shared-config]', $('#flowSharedInputFields')).forEach(field => {
|
||||
const key = field.dataset.sharedConfig;
|
||||
let value = field.value;
|
||||
if (kind === 'constant' && key === 'value') value = value === 'true';
|
||||
else if (field.type === 'number') value = Number(value);
|
||||
config[key] = value;
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
function renderLogRetention() {
|
||||
const select = $('#logRetentionDays'); if (!select || !app.settings) return;
|
||||
[...select.options].forEach(option => { option.textContent = `${option.value} ${tr('common.days')}`; });
|
||||
@@ -176,6 +260,7 @@ function renderHomeAssistantSettings() {
|
||||
form.ha_allow_invalid_tls.checked = !!app.settings.home_assistant?.allow_invalid_tls;
|
||||
form.outdoor_assist_enabled.checked = !!app.settings.outdoor_assist_enabled;
|
||||
renderSensorAliases();
|
||||
renderFlowSharedInputs();
|
||||
renderAccessTokens();
|
||||
markFormClean(form);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user