This commit is contained in:
Mateusz Gruszczyński
2026-09-02 09:02:56 +02:00
parent 9c6e51fc35
commit 43441d2fb7
16 changed files with 555 additions and 60 deletions
+49
View File
@@ -300,6 +300,50 @@ $('#addFlowSharedInput')?.addEventListener('click', () => openFlowSharedInputEdi
$('#flowSharedInputKind')?.addEventListener('change', event => {
renderFlowSharedInputFields(event.target.value, flowDefaultConfig(event.target.value));
});
function compareFlowSharedHaValue(actual, operator, expected) {
if (['lt','lte','gt','gte'].includes(operator)) {
const a = Number(actual), b = Number(expected);
if (!Number.isFinite(a) || !Number.isFinite(b)) return false;
if (operator === 'lt') return a < b;
if (operator === 'lte') return a <= b;
if (operator === 'gt') return a > b;
return a >= b;
}
const left = actual == null ? '' : String(actual);
const right = expected == null ? '' : String(expected);
return operator === 'neq' ? left !== right : left === right;
}
function evaluateFlowSharedHaTest(kind, config, result) {
if (kind === 'ha_available') return { actual:result.state, matched:result.available === true };
let actual = result.state;
if (kind === 'ha_attribute') actual = result.attributes?.[config.attribute];
return { actual, matched:compareFlowSharedHaValue(actual, config.operator || 'eq', config.value) };
}
$('#flowSharedInputTest')?.addEventListener('click', async event => {
const form = $('#flowSharedInputForm'), resultHost = $('#flowSharedInputTestResult');
if (!form || !resultHost) return;
const kind = form.kind.value, config = collectFlowSharedInputConfig(kind);
const entityId = String(config.entity_id || '').trim();
if (!entityId) return toast(tr('flow.sharedInputTestEntityRequired'), true);
const button = event.currentTarget, idle = button.textContent;
button.disabled = true; button.textContent = tr('flow.sharedInputTesting');
resultHost.hidden = false; resultHost.innerHTML = `<span>${esc(tr('flow.sharedInputTesting'))}</span>`;
try {
const result = await api('/api/integrations/home-assistant/entity', { method:'POST', body:{ entity_id:entityId } });
const evaluation = evaluateFlowSharedHaTest(kind, config, result);
const actual = evaluation.actual == null ? 'null' : (typeof evaluation.actual === 'object' ? JSON.stringify(evaluation.actual) : String(evaluation.actual));
const expectation = kind === 'ha_available' ? tr('flow.sharedInputTestAvailable') : `${config.operator || 'eq'} ${config.value ?? ''}`;
resultHost.classList.toggle('pass', evaluation.matched);
resultHost.classList.toggle('fail', !evaluation.matched);
resultHost.innerHTML = `<div><strong>${esc(evaluation.matched ? tr('flow.sharedInputTestMatched') : tr('flow.sharedInputTestNotMatched'))}</strong><span class="badge ${evaluation.matched ? 'active' : ''}">${esc(result.available ? tr('flow.sharedInputTestAvailable') : tr('flow.sharedInputTestUnavailable'))}</span></div><dl><div><dt>${esc(tr('flow.sharedInputTestCurrent'))}</dt><dd><code>${esc(actual)}</code></dd></div><div><dt>${esc(tr('flow.sharedInputTestExpected'))}</dt><dd><code>${esc(expectation)}</code></dd></div></dl><small>${esc(result.entity_id)}${result.last_updated ? ` · ${esc(dateTime(result.last_updated))}` : ''}</small>`;
} catch (error) {
resultHost.classList.remove('pass'); resultHost.classList.add('fail');
resultHost.innerHTML = `<strong>${esc(tr('flow.sharedInputTestUnavailable'))}</strong><span>${esc(error.message)}</span>`;
} finally { button.disabled = false; button.textContent = idle; }
});
$('#flowSharedInputForm')?.addEventListener('submit', event => {
event.preventDefault();
const form = event.currentTarget;
@@ -318,6 +362,11 @@ $('#flowSharedInputForm')?.addEventListener('submit', event => {
document.addEventListener('click', event => {
const edit = event.target.closest?.('[data-flow-shared-edit]');
if (edit) { openFlowSharedInputEditor(edit.dataset.flowSharedEdit); return; }
const openFlow = event.target.closest?.('[data-open-shared-flow]');
if (openFlow) {
if (showView('flows')) requestAnimationFrame(() => openFlowEditor(openFlow.dataset.openSharedFlow));
return;
}
const remove = event.target.closest?.('[data-flow-shared-delete]');
if (!remove) return;
const id = remove.dataset.flowSharedDelete;