From 912e6a62b65517fb4124ebefc92bc896e6dabc05 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Mon, 13 Jul 2026 11:41:11 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20v0.126.0=20UI=20uniformity=20bundle=20?= =?UTF-8?q?=E2=80=94=20CHANGELOG=20(parts=20A-E=20+=20gate=20housekeeping)?= =?UTF-8?q?,=20REUSE=20(app=5Flist=5Frow=20canonical=20row=20+=20gate=20li?= =?UTF-8?q?st),=20README=20(shared-row=20pattern,=20infra=20identity,=20Pa?= =?UTF-8?q?rt=20E=20display=20pick),=20CONTEXT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 40 +++++++++++++++++++++++++++++++++++++++- CONTEXT.md | 21 ++++++++++++++++++++- REUSE.md | 3 ++- controller/README.md | 16 +++++++++++++--- 4 files changed, 74 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1e1162..510837c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,48 @@ ### v0.126.0 — UI uniformity bundle: shared app-list rows, infra-app metadata, restore-form polish, mojibake gate (2026-07-13) +Operator review (2026-07-13 screenshots): app lists looked designed three different ways across +four+ surfaces; infra stacks rendered as bare names; the .fab password input clipped its +placeholder; the zero-toggle run-warning went stale. Controller-only, presentation-layer — NO +backup/engine/toggle behavior change (render tests assert the action markup is untouched). + +- **Part A — ONE row grammar, four surfaces:** `templates/app_row.html` defines + `app_list_row`/`app_list_row_end` (the layout_start/_end idiom): icon + name (+ optional + one-line secondary) left, caller action block right; compact 44px row. Applied to the Távoli + mentés toggle list, the Visszaállítás restore-to-verify + .fab lists and the dashboard + Telepített alkalmazások (state edge + data-href preserved); the Alkalmazások collapsed + headers ALIGNED to the grammar (icon+name left, status dot moved right before the chevron; + expander untouched — the one allowlisted aligned copy). funcmap: `dict` + `appHref`; + `OffboxAppRow`/`AppBackupRow` gain `Slug`. Old `.stack-card`/`.storage-path-item` row CSS+markup + retired. **NEW gate `scripts/app_row_dedup_gate.py`** — row markup single-sourced (red-proven: + pasted an old row block back → exit 1). +- **Part B — infra stacks carry identity:** `inframeta.go` static display-only map — + cloudflared → „Cloudflare Tunnel", traefik → „Traefik", filebrowser → „FileBrowser", each with + curated Hungarian description; dashboard rows + app cards show icon + description + the + existing Védett chip. Generic embedded `/static/infra-logo.svg` as icon fallback. filebrowser + is the ONLY Linked stack (files. Megnyitás); guarded WRONG outcome — no customer link + for cloudflared/traefik (render test counts exactly one https:// link; red-proven by flipping + Linked on cloudflared → FAIL). +- **Part C — restore-form polish:** the .fab encryption input is a standard form field — + placeholder „Opcionális jelszó" + helper under the field („Üresen hagyva a csomag titkosítás + nélkül készül."); the import-page bundle-password input picks up `.form-input` (was a bare + browser default). +- **Part D — mojibake fixed-by-construction:** byte-level sweep found ZERO double-encoded + literals in the committed source — the live „Tárhely"-class text on the import page is the + felhom-usb DRIVE-LABEL DATA (settings.json), repaired via the label-edit UI during live + validation. **NEW gate `scripts/mojibake_gate.py`** (Python per the multibyte rule): all + templates + Go sources must strict-UTF-8-decode and contain none of Ã Â Ă ă ˘ ˇ; allowlist + ZERO. Red-proven (reintroduced „Tárhely" → exit 1 naming file:line). +- **Part E — the stale zero-toggle line tells the truth:** `offboxWarningDisplay` display pick + (no state mutation): a persisted „nincs mentésre jelölt alkalmazás" run-warning is replaced by + „A kijelölés módosult az utolsó futás óta — a következő távoli mentés már tartalmazza." once + ≥1 app is toggled (rendered neutral — reassurance, not deviation); 0 toggled keeps the + v0.123.0 line verbatim; quota/partial warnings pass through. Red-proven at unit + render level. - **Gate housekeeping (first commit):** `scripts/backups_split_move_check.py` retired — the one-shot v0.124.0 migration gate served its purpose (it pinned the split to verbatim moves vs df7ad37); this release legitimately rewrites those blocks onto the shared row partial. All - other template gates stay mandatory. + other template gates stay mandatory (template_id, emoji, native_confirm, offbox_rename, + docker_run_volume_path + the two new ones). ### v0.125.0 — .fab volume export/import: containerized path-strand data loss FIXED (IA finding 1, HIGH) (2026-07-13) — MinAgent: 0.81.0 diff --git a/CONTEXT.md b/CONTEXT.md index fc063a2..442f065 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -7,7 +7,26 @@ > > Ask Claude Code: "Please update CONTEXT.md with what we did today" -Last updated: 2026-07-13 (v0.125.0 — .fab volume path-strand fix) +Last updated: 2026-07-13 (v0.126.0 — UI uniformity bundle) + +> **2026-07-13 — v0.126.0: UI UNIFORMITY BUNDLE (shared app-list rows + infra identity + +> restore-form polish + mojibake gate + honest stale line). Presentation-layer only — NO +> backup/toggle/engine behavior change. MinAgent 0.81 + floor unchanged.** +> (A) `templates/app_row.html` `app_list_row`/`app_list_row_end` is THE canonical list row +> (icon+name left, caller action right, compact 44px) — dashboard installed-apps, Távoli mentés +> toggles, Visszaállítás restore-to-verify + .fab lists render through it; the backups-apps +> expander header is ALIGNED (own markup, allowlisted); gate `scripts/app_row_dedup_gate.py` +> (red-proven). funcmap: `dict`/`appHref`/`infraMeta`. (B) `inframeta.go`: cloudflared → +> „Cloudflare Tunnel", traefik → „Traefik", filebrowser → „FileBrowser" + Hungarian descriptions +> + generic `/static/infra-logo.svg` fallback; filebrowser = the ONLY Linked infra +> (files.); render test counts exactly one customer link (red-proven). (C) .fab password +> field standard („Opcionális jelszó" + helper; import-page input got `.form-input`). +> (D) `scripts/mojibake_gate.py` — templates+Go strict UTF-8, zero Ã/Â/Ă-signature chars, +> allowlist ZERO (red-proven); source had NO mojibake — the live „Tárhely" is the felhom-usb +> drive-label DATA, repaired via the label-edit UI (live step). (E) `offboxWarningDisplay` +> display pick — stale „nincs mentésre jelölt alkalmazás" run-warning → „A kijelölés módosult…" +> note once ≥1 app toggled (neutral color); 0 toggled unchanged (red-proven). +> Housekeeping: one-shot `backups_split_move_check.py` RETIRED (served its purpose). > **2026-07-13 — v0.125.0: .FAB VOLUME PATH-STRAND DATA LOSS FIXED (IA finding 1, HIGH). > MinAgent 0.81 unchanged; floor may advance to 0.125.0 next train (must NOT halt above 0.124.0 diff --git a/REUSE.md b/REUSE.md index 7d79024..62a3c6b 100644 --- a/REUSE.md +++ b/REUSE.md @@ -207,10 +207,11 @@ Cross-repo edges: - **New REST endpoint**: path dispatch in `Router.ServeHTTP` (controller/internal/api/router.go); use `writeJSON` + `limitBody`. - **New background job**: `sched.Every`/`sched.Daily` registration block in controller/cmd/controller/main.go. - **New template function**: `Server.templateFuncMap` (controller/internal/web/funcmap.go) — obey v2 state-suffix vocabulary. -- **New page/nav item**: `baseData` + sidebar in controller/internal/web/templates/ (nested sub-links pattern `.nav-links-nested`); must pass `controller/scripts/template_id_gate.py` + `controller/scripts/emoji_gate.py` + `controller/scripts/native_confirm_gate.py` + `controller/scripts/offbox_rename_gate.py`. +- **New page/nav item**: `baseData` + sidebar in controller/internal/web/templates/ (nested sub-links pattern `.nav-links-nested`); must pass `controller/scripts/template_id_gate.py` + `controller/scripts/emoji_gate.py` + `controller/scripts/native_confirm_gate.py` + `controller/scripts/offbox_rename_gate.py` + `controller/scripts/app_row_dedup_gate.py` + `controller/scripts/mojibake_gate.py`. - **Docker volume tar streaming (v0.125.0)**: `appexport.dockerExec` (seam, package var) + `withVolumeHelper`/`exportVolumeTar`/`importVolumeTar` — stream volume content via `docker cp` through a stopped helper container. NEVER `docker run -v ` — the daemon resolves `-v` host-side and strands the data when the controller is containerized (the v0.124.0 HIGH finding); `controller/scripts/docker_run_volume_path_gate.py` enforces (every `"-v"` allowlisted with its WHY). - **Guarded file download (v0.124.0)**: `handler_export_download.go` — the canonical shape for streaming a server-side file to the browser: accept a BASENAME only (shape regexp + no separators/`..`), `filepath.Join` then assert `filepath.Dir(path) == dir`, `io.Copy` (never ReadAll), `Content-Disposition: attachment`, remove after a successful stream, TTL sweep (`sweepFabDownloads(dir, now, maxAge, logger)` — now injected for tests). Red-proof the guard by loosening to prefix-matching (the `..` case must fail). - **Backups sub-page data**: `backupsCommonData(page, title, r)` + `backupsOffboxData(data)` (handlers.go) — the ONLY builders for the four `/backups*` pages; a new backups section extends these, never re-derives in a page handler. (The one-shot v0.124.0 move gate `backups_split_move_check.py` was retired in v0.126.0.) +- **App-list row (v0.126.0)**: `app_list_row`/`app_list_row_end` in `templates/app_row.html` is THE canonical list pattern — icon+name(+secondary) left, caller action block right; open with `dict "Slug" ... "Name" ...` (optional `Secondary`/`RowClass`/`Href`/`FallbackIcon`), close with `app_list_row_end`. Do NOT hand-roll app rows — `scripts/app_row_dedup_gate.py` enforces single-sourcing (the backups_apps expander header is the one allowlisted aligned copy). Infra display identity: `inframeta.go` map + `infraMeta` func (filebrowser is the only Linked stack). - **Consequential-action confirm (LIGHT)**: `felhomConfirm(el, question, onYes)` in layout.html (v0.123.0) — the trigger swaps in place to "kérdés + Igen/Mégse"; form buttons opt in with `data-confirm="…"` (delegated listener, `requestSubmit` keeps formaction/name-value). NEVER native `confirm()`/`prompt()` (OS-modals freeze browser automation — drill F-11; `native_confirm_gate.py` enforces). Heavy destructive flows keep the `.confirm-overlay` `openDialog` pattern. - **New hub event**: typed `Notify*` wrapper on Notifier + hub allowlist entry (cross-repo). - **New app integration**: `integrations.Manager.RegisterHandler` with `IntegrationKey(provider, target)`. diff --git a/controller/README.md b/controller/README.md index 1489e2a..af1aa57 100644 --- a/controller/README.md +++ b/controller/README.md @@ -123,9 +123,19 @@ backups, monitoring and notifications. All Proxmox/disk operations are delegated (`felhomConfirm` in layout.html, v0.123.0: the trigger swaps in place to "kérdés + Igen/Mégse"; form buttons opt in via `data-confirm="…"`) — never native `confirm()`/`prompt()` (OS-modals freeze browser automation; drill F-11). + **Shared app-list row (v0.126.0):** `templates/app_row.html` (`app_list_row`/`app_list_row_end`) + is the ONE row grammar for app lists — icon + name (+ optional secondary line) left, caller + action block right; used by the dashboard installed-apps list, the Távoli mentés toggle list + and the Visszaállítás restore-to-verify/.fab lists; the backups-apps expander header is + ALIGNED to the same grammar (own markup — it carries the toggle). Protected infra stacks + (traefik/cloudflared/filebrowser) get curated Hungarian display identity from the + `inframeta.go` map (name + description + generic `/static/infra-logo.svg` fallback icon); + filebrowser is the only infra stack with a customer link (`files.`). **Enforcement:** `scripts/template_id_gate.py` (JS element-ID integrity) + `scripts/emoji_gate.py` - (no emoji) + `scripts/native_confirm_gate.py` (zero native confirm/prompt) — run after any - template change; the Go `TestNoEmojiInTemplates` mirrors the emoji gate. + (no emoji) + `scripts/native_confirm_gate.py` (zero native confirm/prompt) + + `scripts/app_row_dedup_gate.py` (row markup single-sourced) + `scripts/mojibake_gate.py` + (no double-encoded UTF-8 in templates/Go sources) — run after any template change; the Go + `TestNoEmojiInTemplates` mirrors the emoji gate. - **Europe/Budapest timezone** — All scheduled jobs, timestamps, and UI labels use Hungarian timezone. ### Module Map @@ -361,7 +371,7 @@ self-sufficient backup** — any single tier can fully restore an app. | Route | Page | Sections | |-------|------|----------| | `/backups` | Áttekintés | storage overview, whole-guest Rendszermentés, status stat cards, single-copy warning | -| `/backups/remote` | Távoli mentés | Felhom-offsite status card (3 states, display-only), tier-3 status block + quota, participation toggles (+ zero-toggle hint), manual-target form (`#offbox-section`) | +| `/backups/remote` | Távoli mentés | Felhom-offsite status card (3 states, display-only), tier-3 status block + quota, participation toggles (+ zero-toggle hint; the persisted zero-toggle run-warning is DISPLAY-replaced by a "kijelölés módosult" note once ≥1 app is toggled — `offboxWarningDisplay`, v0.126.0), manual-target form (`#offbox-section`) | | `/backups/apps` | Alkalmazások | schedule, Adatbázisok table, per-app 1./2./3. tier rows (tier-2 config entry; tier-3 actions deep-link to `/backups/remote#offbox-section`) | | `/backups/restore` | Visszaállítás | restore panel, offbox restore-to-verify list, .fab download/import loop |