Expand room planning management
Some checks failed
quality / test (3.11) (push) Has been cancelled
quality / test (3.13) (push) Has been cancelled

This commit is contained in:
2026-07-26 23:12:49 +02:00
parent 9ff005f089
commit 1788f9d963
7 changed files with 380 additions and 16 deletions

View File

@@ -1410,14 +1410,24 @@ function renderRoomManagement() {
const rooms = (overview.rooms || []).filter(room =>
!query
|| normalizedSearch(room.room).includes(query)
|| (room.actuators || []).some(actuator =>
matchesSearch({
entity_id: actuator.actuator_entity_id,
friendly_name: actuator.friendly_name,
area_name: room.room,
}, query)
)
);
|| (room.actuators || []).some(actuator =>
matchesSearch({
entity_id: actuator.actuator_entity_id,
friendly_name: actuator.friendly_name,
area_name: room.room,
}, query)
)
|| (room.sensors || []).some(sensor =>
matchesSearch({
entity_id: sensor.entity_id,
friendly_name: sensor.friendly_name,
area_name: room.room,
}, query)
)
|| (room.suggested_actions || []).some(action =>
normalizedSearch(`${action.category} ${action.title} ${action.when} ${action.then}`).includes(query)
)
);
const unmanaged = overview.unmanaged_actuators || [];
box.innerHTML = `
${rooms.length ? rooms.map(room => `
@@ -1425,9 +1435,9 @@ function renderRoomManagement() {
<header>
<div>
<h3>${escapeHtml(room.room)}</h3>
<p class="muted">${escapeHtml(room.actuator_count)} ${escapeHtml(uiLang === "en" ? "actuator(s)" : "Aktor(en)")}</p>
<p class="muted">${escapeHtml(room.actuator_count)} ${escapeHtml(uiLang === "en" ? "actuator(s)" : "Aktor(en)")} · ${escapeHtml(room.sensor_count || 0)} ${escapeHtml(uiLang === "en" ? "sensor(s)" : "Sensor(en)")}</p>
</div>
<span class="chip">${escapeHtml((room.sensors || []).filter(sensor => sensor.active).length)} ${escapeHtml(uiLang === "en" ? "active sensors" : "aktive Sensoren")}</span>
<span class="chip">${escapeHtml(room.action_count || 0)} ${escapeHtml(uiLang === "en" ? "actions" : "Handlungen")}</span>
</header>
<div class="sensor-strip">
${(room.sensors || []).slice(0, 12).map(sensor => sensorPill(sensor)).join("") || `<span class="muted">${escapeHtml(uiLang === "en" ? "No sensors selected yet." : "Noch keine Sensoren ausgewählt.")}</span>`}
@@ -1435,6 +1445,7 @@ function renderRoomManagement() {
<div class="decision-list">
${(room.prediction_rules || []).slice(0, 5).map(rule => `<div class="decision-row">${escapeHtml(rule)}</div>`).join("")}
</div>
${roomActions(room.suggested_actions || [])}
<div class="card-list">
${(room.actuators || []).map(actuator => roomActuatorCard(actuator)).join("")}
</div>
@@ -1515,6 +1526,7 @@ function roomActuatorCard(actuator) {
<div class="decision-list">
${(actuator.prediction_rules || []).slice(0, 4).map(rule => `<div class="decision-row">${escapeHtml(rule)}</div>`).join("")}
</div>
${roomActions(actuator.suggested_actions || [])}
<div class="actions">
<button class="secondary" onclick="showActuator('${escapeHtml(actuator.actuator_entity_id)}')">${escapeHtml(uiLang === "en" ? "Open details" : "Details öffnen")}</button>
<button onclick="saveRoomAssignment('${escapeHtml(actuator.actuator_entity_id)}', '${escapeHtml(actuator.selected_numeric_entity_id || "")}', '${escapeHtml(selectedContextIds.join(","))}')">${escapeHtml(uiLang === "en" ? "Save selection" : "Auswahl speichern")}</button>
@@ -1524,6 +1536,21 @@ function roomActuatorCard(actuator) {
`;
}
function roomActions(actions) {
if (!actions.length) return "";
return `
<div class="decision-list">
${actions.slice(0, 6).map(action => `
<div class="decision-row" title="${escapeHtml(action.why)}">
<strong>${escapeHtml(action.title)}</strong>
<span class="muted"> · ${escapeHtml(action.category)} · ${Math.round((action.confidence || 0) * 100)} %</span><br>
${escapeHtml(action.when)} -> ${escapeHtml(action.then)}
</div>
`).join("")}
</div>
`;
}
async function saveRoomAssignment(actuatorId, numericEntityId, contextCsv) {
const contextEntityIds = contextCsv.split(",").map(item => item.trim()).filter(Boolean);
try {