Fix dashboard text overflow and close v1 docs gaps
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.5 - 2026-06-17
|
||||
- Lange Friendly Names, Entity-IDs, Chips, Tabellenwerte und Metriken brechen
|
||||
im Dashboard responsiv um und laufen nicht mehr aus Karten oder Boxen.
|
||||
- Automatisierter Performance-Budget-Test fuer Root-HTML und
|
||||
`/v1/actuators/dashboard` gegen das 5-Sekunden-Limit ergaenzt.
|
||||
- HA-/Ingress-Verifikation mit Supervisor-Status, Backup, Watchdog,
|
||||
Hard-Reload und Rollback im Operating Guide dokumentiert.
|
||||
|
||||
## 1.0.4 - 2026-06-17
|
||||
- Sensor-Relevanz ist in der Aktor-Detailansicht sichtbar: automatische
|
||||
Relevanz, aktive Gewichtung und Score werden pro verwendetem Sensor/Zustand
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: SillyHome Next
|
||||
version: "1.0.4"
|
||||
version: "1.0.5"
|
||||
slug: sillyhome_next
|
||||
description: Lernt automatisch aus deinem Verhalten und steuert freigegebene Aktoren
|
||||
url: http://192.168.6.31:3000/pino/sillyhome-next
|
||||
|
||||
@@ -105,7 +105,7 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]:
|
||||
app = FastAPI(
|
||||
title="SillyHome Next API",
|
||||
description="Lokales Smart-Home-Intelligenzsystem für Home Assistant.",
|
||||
version="1.0.4",
|
||||
version="1.0.5",
|
||||
lifespan=lifespan,
|
||||
)
|
||||
app.state.settings = load_settings()
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
--bad:#8fb8ff;
|
||||
}
|
||||
* { box-sizing:border-box; }
|
||||
html, body { max-width:100%; overflow-x:hidden; }
|
||||
body { margin:0; font-size:15px; background:var(--panel-quiet); }
|
||||
h1,h2,h3 { margin:0 0 10px; letter-spacing:0; }
|
||||
p { margin:6px 0; }
|
||||
@@ -76,26 +77,29 @@
|
||||
button.secondary { background:var(--complement-soft); color:#dff6ff; border:1px solid #22607c; }
|
||||
button.danger { background:#2a3441; color:#f2f6fb; border:1px solid #536273; }
|
||||
button.compact { width:auto; min-width:112px; margin-right:8px; padding:8px 10px; min-height:36px; }
|
||||
table { width: 100%; border-collapse: collapse; font-size: .92rem; }
|
||||
td,th { padding: 8px; border-bottom: 1px solid #2d3a47; text-align: left; vertical-align: top; }
|
||||
table { width: 100%; border-collapse: collapse; table-layout:fixed; font-size: .92rem; }
|
||||
td,th { padding: 8px; border-bottom: 1px solid #2d3a47; text-align: left; vertical-align: top; overflow-wrap:anywhere; word-break:break-word; }
|
||||
ul { margin: 8px 0; padding-left: 18px; }
|
||||
.notice { border-left:4px solid var(--complement); padding-left:10px; }
|
||||
.grid-two { display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:12px; }
|
||||
.chips { display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
|
||||
.chip { padding:4px 8px; border-radius:8px; background:#222b36; border:1px solid var(--border); font-size:.85rem; }
|
||||
.chip { padding:4px 8px; border-radius:8px; background:#222b36; border:1px solid var(--border); font-size:.85rem; max-width:100%; overflow-wrap:anywhere; word-break:break-word; }
|
||||
.muted { color:var(--text-soft); }
|
||||
.card-list { display:grid; grid-template-columns:repeat(auto-fit,minmax(250px,1fr)); gap:10px; }
|
||||
.actuator-card { background:#121922; border:1px solid var(--border); border-radius:8px; padding:10px; min-width:0; }
|
||||
.actuator-card.selected { border-color:var(--complement); box-shadow:0 0 0 1px rgba(28,199,255,.35); }
|
||||
.card-title { display:flex; justify-content:space-between; gap:10px; align-items:flex-start; margin-bottom:8px; }
|
||||
.entity-id { overflow-wrap:anywhere; font-weight:800; }
|
||||
.card-title { display:flex; flex-wrap:wrap; justify-content:space-between; gap:10px; align-items:flex-start; margin-bottom:8px; min-width:0; }
|
||||
.card-title > div { min-width:0; flex:1 1 160px; overflow-wrap:anywhere; word-break:break-word; }
|
||||
.card-title .chip { flex:0 1 auto; white-space:normal; text-align:center; }
|
||||
.actuator-card strong { overflow-wrap:anywhere; word-break:break-word; }
|
||||
.entity-id { overflow-wrap:anywhere; word-break:break-word; font-weight:800; }
|
||||
.metric-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(120px,1fr)); gap:6px; margin:8px 0; }
|
||||
.metric { background:var(--panel-soft); border:1px solid var(--border); border-radius:8px; padding:8px; min-width:0; }
|
||||
.metric { background:var(--panel-soft); border:1px solid var(--border); border-radius:8px; padding:8px; min-width:0; overflow-wrap:anywhere; word-break:break-word; }
|
||||
.metric strong { display:block; margin-bottom:4px; color:#cfe0ec; font-size:.84rem; }
|
||||
.actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
|
||||
.actions button { flex:1 1 180px; margin-top:0; }
|
||||
.detail-header { display:flex; justify-content:space-between; gap:12px; align-items:flex-start; flex-wrap:wrap; }
|
||||
.manual-context { margin-top:12px; background:#121922; border:1px solid var(--border); border-radius:8px; padding:10px; }
|
||||
.manual-context { margin-top:12px; background:#121922; border:1px solid var(--border); border-radius:8px; padding:10px; min-width:0; overflow-wrap:anywhere; word-break:break-word; }
|
||||
.inline-controls { display:grid; grid-template-columns:repeat(auto-fit,minmax(160px,1fr)); gap:8px; margin:8px 0; }
|
||||
.manual-entry { min-height:80px; resize:vertical; }
|
||||
textarea { width:100%; border-radius:8px; border:1px solid #3b4b5b; padding:12px; background:#101820; color:#fff; font:inherit; }
|
||||
|
||||
@@ -101,6 +101,21 @@ wget -qO /tmp/summary.json http://58adbe1e-sillyhome-next:8000/v1/actuators/summ
|
||||
wget -qO /tmp/dashboard.json http://58adbe1e-sillyhome-next:8000/v1/actuators/dashboard
|
||||
```
|
||||
|
||||
Wenn der Add-on-Container aus dem Agent-Host nicht direkt routbar ist, gilt der
|
||||
Home-Assistant-Supervisor als Verifikationsquelle:
|
||||
|
||||
- Add-on-Info pruefen: Version, `version_latest`, `update_available`, `state`,
|
||||
`boot` und `watchdog`.
|
||||
- Vor Updates eine Home-Assistant-Teil-Sicherung fuer **SillyHome Next**
|
||||
erstellen.
|
||||
- Nach einem Store-Reload und Update muss `version == version_latest`,
|
||||
`update_available == false`, `state == started`, `boot == auto` und
|
||||
`watchdog == true` gelten.
|
||||
- Den HA-/Ingress-Tab nach jedem Update hart neu laden, weil Home Assistant
|
||||
sonst alte HTML-/JavaScript-Ressourcen aus dem bestehenden Tab verwenden kann.
|
||||
- Rollback erfolgt ueber die vorherige Add-on-Teil-Sicherung oder den letzten
|
||||
Git-Tag; beide Referenzen im Release-/Abnahmeprotokoll notieren.
|
||||
|
||||
## Rollback
|
||||
|
||||
Der stabile Vor-1.0-Stand ist `v0.7.21`. Vor dem 1.0.0-Umbau wurde ein
|
||||
|
||||
@@ -44,6 +44,12 @@ expliziter Freigabe.
|
||||
- `ruff check .`
|
||||
- `mypy app backend tests`
|
||||
- `git diff --check`
|
||||
- Performance-Budget:
|
||||
- Automatisierter Test prueft Root-HTML und `/v1/actuators/dashboard` gegen
|
||||
das 5-Sekunden-Budget mit kontrollierten Fake-HA-/Cache-Daten.
|
||||
- HA-/Ingress-Verifikation:
|
||||
- Supervisor-Update, Add-on-Status, Watchdog, Backup, Ingress-Hard-Reload
|
||||
und Rollback sind im Operating Guide dokumentiert.
|
||||
|
||||
## Teilweise Erfuellt
|
||||
|
||||
@@ -62,14 +68,10 @@ expliziter Freigabe.
|
||||
|
||||
## Offen Fuer v1.0.x
|
||||
|
||||
- Echte Dashboard-Performance-Budget-Tests, die Start-HTML und
|
||||
`/v1/actuators/dashboard` gegen ein 5-Sekunden-Limit messen.
|
||||
- Dashboard-Jobstatus fuer Reconciliation, Training, Discovery und
|
||||
Automation-Refresh.
|
||||
- Mehr Entscheidungsstatistik pro Aktor: welche Sensoren wie stark
|
||||
beigetragen haben, wie sich Confidence und Sample Count entwickeln.
|
||||
- Dokumentierte HA-Installationspruefung mit Supervisor-/Ingress-Hinweisen,
|
||||
weil direkte Container-HTTP-Pruefung ausserhalb HA nicht immer routbar ist.
|
||||
|
||||
## Rollback
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "sillyhome-next"
|
||||
version = "1.0.4"
|
||||
version = "1.0.5"
|
||||
description = "Lokales Smart-Home-Intelligenzsystem für Home Assistant"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from time import perf_counter
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
|
||||
@@ -299,6 +300,26 @@ def test_dashboard_overview_uses_cache_without_ha_roundtrip(tmp_path: Path) -> N
|
||||
assert payload["discovery_groups"]
|
||||
|
||||
|
||||
def test_dashboard_start_path_stays_within_five_second_budget(tmp_path: Path) -> None:
|
||||
with TestClient(app) as client:
|
||||
_install_service(tmp_path)
|
||||
client.get("/v1/actuators/discovery")
|
||||
client.post("/v1/actuators", json={"actuator_entity_id": "light.abstellkammer"})
|
||||
|
||||
root_started_at = perf_counter()
|
||||
root_response = client.get("/")
|
||||
root_elapsed = perf_counter() - root_started_at
|
||||
|
||||
dashboard_started_at = perf_counter()
|
||||
dashboard_response = client.get("/v1/actuators/dashboard")
|
||||
dashboard_elapsed = perf_counter() - dashboard_started_at
|
||||
|
||||
assert root_response.status_code == 200
|
||||
assert dashboard_response.status_code == 200
|
||||
assert root_elapsed < 5.0
|
||||
assert dashboard_elapsed < 5.0
|
||||
|
||||
|
||||
def test_discovery_reads_entities_once_and_reuses_them(tmp_path: Path) -> None:
|
||||
with TestClient(app) as client:
|
||||
_install_service(tmp_path)
|
||||
|
||||
Reference in New Issue
Block a user