mirror of
https://github.com/myronblair/jarvis
synced 2026-06-30 17:50:23 -05:00
fix: HA admin panel — remove entity ID column, add toggle controls, filter unavailable
This commit is contained in:
@@ -626,7 +626,7 @@ select.filter-sel:focus{border-color:var(--cyan)}
|
||||
<select class="filter-sel" id="ha-domain" onchange="loadHA()"><option value="">ALL</option></select>
|
||||
<button class="filter-btn active" id="ha-all-btn" onclick="setHAOnlyOn(false,this)">ALL</button>
|
||||
<button class="filter-btn" id="ha-on-btn" onclick="setHAOnlyOn(true,this)">ON ONLY</button>
|
||||
<input id="ha-search" placeholder="search name or entity_id..." style="background:#060a0e;border:1px solid var(--border2);color:var(--text);padding:4px 8px;font-family:var(--font);font-size:0.65rem;width:220px;outline:none" oninput="filterHATable()" onchange="filterHATable()">
|
||||
<input id="ha-search" placeholder="search by name..." style="background:#060a0e;border:1px solid var(--border2);color:var(--text);padding:4px 8px;font-family:var(--font);font-size:0.65rem;width:200px;outline:none" oninput="filterHATable()" onchange="filterHATable()">
|
||||
<span class="lbl" id="ha-count" style="color:var(--cyan)"></span>
|
||||
</div>
|
||||
<div class="tbl-wrap" id="ha-tbl"><div class="loading">SCANNING...</div></div>
|
||||
@@ -1290,23 +1290,45 @@ function filterHATable() {
|
||||
}
|
||||
|
||||
function renderHATable(entities) {
|
||||
if (!entities.length) { document.getElementById('ha-tbl').innerHTML='<div class="empty">NO ENTITIES</div>'; return; }
|
||||
const domainColors = {light:'#ffcc00',switch:'#00d4ff',binary_sensor:'#39ff14',sensor:'#9b9bff',media_player:'#ff8800',alarm_control_panel:'#ff3333',camera:'#888'};
|
||||
let rows = entities.map(e => {
|
||||
const on = ['on','home','open','playing','mowing','active'].includes(e.state);
|
||||
const avail = entities.filter(e => e.state !== 'unavailable' && e.state !== 'unknown');
|
||||
if (!avail.length) { document.getElementById('ha-tbl').innerHTML='<div class="empty">NO ENTITIES</div>'; return; }
|
||||
const domainColors = {light:'#ffcc00',switch:'#00d4ff',media_player:'#ff8800',alarm_control_panel:'#ff3333',scene:'#00d4ff',lawn_mower:'#39ff14',water_heater:'#ff8800',fan:'#9b9bff'};
|
||||
const domainIcon = {light:'\u{1F4A1}',switch:'\u{1F50C}',scene:'\u{1F3AC}',media_player:'\u{1F4FA}',alarm_control_panel:'\u{1F512}',lawn_mower:'\u{1F33F}',water_heater:'\u{1F321}',fan:'\u{1F4A8}'};
|
||||
let rows = avail.map(e => {
|
||||
const on = ['on','home','open','playing','mowing','armed_home','armed_away','armed_night','active'].includes(e.state);
|
||||
const isScene = e.domain === 'scene';
|
||||
const dc = domainColors[e.domain] || 'var(--dim)';
|
||||
const icon = domainIcon[e.domain] || '•';
|
||||
const stateLabel = isScene ? '—' : (on ? 'ON' : 'OFF');
|
||||
const ctrl = isScene
|
||||
? `<button class="btn btn-xs" onclick="haToggle('${e.entity_id.replace(/'/g,"\\'")}','${e.state}',this)">▶ RUN</button>`
|
||||
: `<label style="position:relative;display:inline-block;width:30px;height:15px;cursor:pointer">
|
||||
<input type="checkbox" style="opacity:0;width:0;height:0;position:absolute" ${on?'checked':''} onchange="haToggle('${e.entity_id.replace(/'/g,"\\'")}','${e.state}',this.parentElement)">
|
||||
<span id="sl-${e.entity_id.replace(/[^a-z0-9]/gi,'_')}" style="position:absolute;inset:0;border-radius:8px;background:${on?'rgba(0,255,100,0.22)':'rgba(255,255,255,0.08)'};border:1px solid ${on?'var(--green)':'rgba(255,255,255,0.14)'};transition:all .18s">
|
||||
<span style="position:absolute;left:${on?'17':'2'}px;top:2px;width:9px;height:9px;border-radius:50%;background:${on?'var(--green)':'var(--dim)'};transition:all .18s"></span>
|
||||
</span>
|
||||
</label>`;
|
||||
return `<tr>
|
||||
<td><span style="color:${dc};font-size:0.6rem">${esc(e.domain)}</span></td>
|
||||
<td style="width:28px;text-align:center;font-size:0.85rem">${icon}</td>
|
||||
<td><span style="color:${dc};font-size:0.58rem;letter-spacing:1px">${esc(e.domain)}</span></td>
|
||||
<td>${esc(e.name||e.entity_id)}</td>
|
||||
<td style="font-size:0.65rem;color:var(--dim)">${esc(e.entity_id)}</td>
|
||||
<td><span class="badge ${on?'badge-green':'badge-dim'}">${esc(e.state)}</span></td>
|
||||
<td style="text-align:center"><span class="badge ${on?'badge-green':'badge-dim'}">${stateLabel}</span></td>
|
||||
<td style="text-align:center">${ctrl}</td>
|
||||
</tr>`;
|
||||
}).join('');
|
||||
document.getElementById('ha-tbl').innerHTML = `<table>
|
||||
<thead><tr><th>DOMAIN</th><th>NAME</th><th>ENTITY ID</th><th>STATE</th></tr></thead>
|
||||
<thead><tr><th></th><th>DOMAIN</th><th>NAME</th><th>STATE</th><th>CTRL</th></tr></thead>
|
||||
<tbody>${rows}</tbody></table>`;
|
||||
}
|
||||
|
||||
function haToggle(entityId, currentState, el) {
|
||||
el.style.opacity = '0.5';
|
||||
apiPost('ha_toggle', {entity_id: entityId, state: currentState}, () => {
|
||||
el.style.opacity = '1';
|
||||
loadHA();
|
||||
});
|
||||
}
|
||||
|
||||
// ── NEWS ──────────────────────────────────────────────────────────────────────
|
||||
async function loadNews() {
|
||||
document.getElementById('news-custom').innerHTML='<div class="loading">SCANNING...</div>';
|
||||
|
||||
Reference in New Issue
Block a user