diff --git a/CHANGELOG.md b/CHANGELOG.md index 1865324..433c641 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ ## Changelog +### What was just completed (2026-02-18 session 48) +- **v0.13.1 — UI Polish Fixes Round 2 (4 fixes):** + + **Fix 1:** Deploy page "Biztonsági mentés" section now has proper card border. Root cause: `.deploy-cross-drive` used undefined CSS variables `--card-bg` and `--border` (only `--bg-secondary` and `--border-color` exist). Fixed by using correct vars (`style.css`). + + **Fix 2:** Auto-generated env values section cleaned up (`deploy.html`, `style.css`). Badge moved inline with label. "Másolás" buttons removed (native select+copy sufficient). Secret fields keep show/hide toggle. Non-secret fields now plain readonly input without button wrapper. Removed `copyAutoField()` JS. CSS updated: `.form-group-auto` now block layout (was flex row), label uses `display: flex; gap: .5rem`, badge downsized to `0.75rem / normal weight`, readonly inputs get muted background. + + **Fix 3:** Snapshot table n/a → 0 (`backups.html`). Replaced `n/a` with plain `0` in all three stats columns. Removed `.col-na` CSS class (no longer used). + + **Fix 4:** Disk warnings moved from top banner to inline under storage bars (`alerts.go`, `layout.html`, `handlers.go`, `dashboard.html`, `monitoring.html`, `style.css`). Added `Inline bool` field to `Alert` struct. Disk-related warnings set `Inline: true`. Layout banner skips inline alerts. New `GetInlineAlerts(page)` method on `AlertManager`. Dashboard and monitoring handlers pass `DiskWarnings`. Inline warning block rendered below storage bars. New `.inline-warning*` CSS classes (compact, subtle, colored). + + **Files modified (8):** `alerts.go`, `handlers.go`, `templates/style.css`, `templates/dashboard.html`, `templates/backups.html`, `templates/deploy.html`, `templates/monitoring.html`, `templates/layout.html` + ### What was just completed (2026-02-18 session 47) - **v0.13.0 — UI Polish Fixes (8 independent fixes):** diff --git a/controller/internal/web/alerts.go b/controller/internal/web/alerts.go index d28291e..48b632e 100644 --- a/controller/internal/web/alerts.go +++ b/controller/internal/web/alerts.go @@ -19,6 +19,7 @@ type Alert struct { Link string // optional link to relevant page LinkText string // link display text PageOnly []string // if non-empty, only show on these pages (e.g., ["dashboard", "monitoring"]) + Inline bool // if true, rendered by page template inline, not in layout banner } // AlertManager generates and stores dashboard alerts from health check results. @@ -62,10 +63,11 @@ func (am *AlertManager) Refresh(report *monitor.HealthReport, cfg *config.Config Link: "/monitoring", LinkText: "Rendszermonitor", } - // Disk-related warnings only relevant on dashboard and monitoring pages + // Disk-related warnings rendered inline under storage bars, not in top banner if strings.Contains(w, "meghajtón") || strings.Contains(w, "adattároló") || strings.Contains(w, "meghajtó") { alert.ID = "disk-not-separate" alert.PageOnly = []string{"dashboard", "monitoring"} + alert.Inline = true } alerts = append(alerts, alert) } @@ -143,6 +145,30 @@ func (am *AlertManager) GetAlerts(excludeIDs ...string) []Alert { return result } +// GetInlineAlerts returns alerts marked as Inline for a specific page. +func (am *AlertManager) GetInlineAlerts(page string) []Alert { + am.mu.RLock() + defer am.mu.RUnlock() + + var result []Alert + for _, a := range am.alerts { + if !a.Inline { + continue + } + if len(a.PageOnly) == 0 { + result = append(result, a) + continue + } + for _, p := range a.PageOnly { + if p == page { + result = append(result, a) + break + } + } + } + return result +} + // countMissingPings counts how many ping UUIDs are not configured. func countMissingPings(cfg *config.Config) int { count := 0 diff --git a/controller/internal/web/handlers.go b/controller/internal/web/handlers.go index 58149ef..54a8707 100644 --- a/controller/internal/web/handlers.go +++ b/controller/internal/web/handlers.go @@ -124,6 +124,10 @@ func (s *Server) dashboardHandler(w http.ResponseWriter, _ *http.Request) { data["CrossDriveFailed"] = crossDriveFailed } + if s.alertManager != nil { + data["DiskWarnings"] = s.alertManager.GetInlineAlerts("dashboard") + } + s.render(w, "dashboard", data) } @@ -363,6 +367,7 @@ func (s *Server) monitoringHandler(w http.ResponseWriter, _ *http.Request) { // On monitoring page, exclude the "pings-missing" alert since the detailed table is visible if s.alertManager != nil { data["Alerts"] = s.alertManager.GetAlerts("pings-missing") + data["DiskWarnings"] = s.alertManager.GetInlineAlerts("monitoring") } // Ping status section diff --git a/controller/internal/web/templates/backups.html b/controller/internal/web/templates/backups.html index 78a58c0..0bb346f 100644 --- a/controller/internal/web/templates/backups.html +++ b/controller/internal/web/templates/backups.html @@ -356,9 +356,9 @@ {{shortID .SnapshotID}} {{fmtTime .Time}} - {{if .HasStats}}+{{.DataAdded}}{{else}}n/a{{end}} - {{if .HasStats}}{{.FilesNew}}{{else}}n/a{{end}} - {{if .HasStats}}{{.FilesChanged}}{{else}}n/a{{end}} + {{if .HasStats}}+{{.DataAdded}}{{else}}0{{end}} + {{if .HasStats}}{{.FilesNew}}{{else}}0{{end}} + {{if .HasStats}}{{.FilesChanged}}{{else}}0{{end}} {{end}} diff --git a/controller/internal/web/templates/dashboard.html b/controller/internal/web/templates/dashboard.html index 9b40b10..08bc5e9 100644 --- a/controller/internal/web/templates/dashboard.html +++ b/controller/internal/web/templates/dashboard.html @@ -77,6 +77,17 @@ {{end}} + {{if .DiskWarnings}} +
+ {{range .DiskWarnings}} +
+ + {{.Message}} + {{if .Link}}{{.LinkText}} →{{end}} +
+ {{end}} +
+ {{end}} {{end}} diff --git a/controller/internal/web/templates/deploy.html b/controller/internal/web/templates/deploy.html index ab57262..468faf8 100644 --- a/controller/internal/web/templates/deploy.html +++ b/controller/internal/web/templates/deploy.html @@ -260,22 +260,17 @@ {{range .AutoFields}} {{$val := index $autoValues .EnvVar}}
- + {{if and $isDeployed $val}} {{if eq .Type "secret"}}
-
{{else}} -
- - -
+ {{end}} {{end}} - ✓ Automatikusan generálva
{{end}} @@ -461,16 +456,6 @@ function toggleAutoField(fieldId, btn) { el.type = el.type === 'password' ? 'text' : 'password'; btn.textContent = el.type === 'password' ? 'Megjelenítés' : 'Elrejtés'; } -function copyAutoField(fieldId, btn) { - var el = document.getElementById(fieldId); - if (!el) return; - navigator.clipboard.writeText(el.value).then(function() { - var orig = btn.textContent; - btn.textContent = 'Másolva!'; - setTimeout(function() { btn.textContent = orig; }, 2000); - }); -} - function generatePassword(fieldId) { const chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; let pass = ''; diff --git a/controller/internal/web/templates/layout.html b/controller/internal/web/templates/layout.html index 0af9623..06aadcc 100644 --- a/controller/internal/web/templates/layout.html +++ b/controller/internal/web/templates/layout.html @@ -31,7 +31,7 @@ {{if .Alerts}}
{{range .Alerts}} - {{if or (not .PageOnly) (pageMatch .PageOnly $.Page)}} + {{if and (not .Inline) (or (not .PageOnly) (pageMatch .PageOnly $.Page))}}
{{if eq .Level "error"}}🔴{{else if eq .Level "warning"}}🟡{{else}}ℹ️{{end}} {{.Message}} diff --git a/controller/internal/web/templates/monitoring.html b/controller/internal/web/templates/monitoring.html index 62c7421..13f9869 100644 --- a/controller/internal/web/templates/monitoring.html +++ b/controller/internal/web/templates/monitoring.html @@ -63,6 +63,17 @@ {{end}} {{end}}
+ {{if .DiskWarnings}} +
+ {{range .DiskWarnings}} +
+ + {{.Message}} + {{if .Link}}{{.LinkText}} →{{end}} +
+ {{end}} +
+ {{end}}
diff --git a/controller/internal/web/templates/style.css b/controller/internal/web/templates/style.css index 1a8251a..16bc4f9 100644 --- a/controller/internal/web/templates/style.css +++ b/controller/internal/web/templates/style.css @@ -518,16 +518,14 @@ h3 { .form-group { margin-bottom: 1rem; } .form-group label { display: block; font-size: .85rem; font-weight: 500; margin-bottom: .4rem; color: var(--text-primary); } .form-group-auto { - display: flex; - justify-content: space-between; - align-items: center; padding: .5rem .75rem; background: var(--bg-secondary); border: 1px solid var(--border-color); border-radius: 8px; } -.form-group-auto label { margin: 0; } -.auto-generated-badge { color: var(--green); font-size: .8rem; font-weight: 500; } +.form-group-auto label { display: flex; align-items: center; gap: .5rem; margin-bottom: .4rem; } +.form-group-auto .form-control[readonly] { background: var(--bg-primary); } +.auto-generated-badge { color: var(--green); font-size: .75rem; font-weight: normal; } .checkbox-group { display: flex; flex-direction: column; @@ -695,6 +693,37 @@ select.form-control option { background: var(--bg-secondary); color: var(--text- .alert-message { flex: 1; } .alert-link { margin-left: auto; white-space: nowrap; } +/* Inline storage warnings (under storage bars on dashboard and monitoring) */ +.inline-warnings { margin-top: 0.75rem; } +.inline-warning { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.4rem 0.75rem; + margin-top: 0.25rem; + font-size: 0.8rem; + border-radius: 6px; +} +.inline-warning-warning { + color: var(--yellow); + background: rgba(250, 204, 21, 0.06); + border: 1px solid rgba(250, 204, 21, 0.15); +} +.inline-warning-error { + color: var(--red); + background: rgba(218, 54, 51, 0.06); + border: 1px solid rgba(218, 54, 51, 0.15); +} +.inline-warning-dot { font-size: 0.6rem; flex-shrink: 0; } +.inline-warning-text { flex: 1; } +.inline-warning-link { + color: inherit; + opacity: 0.8; + white-space: nowrap; + text-decoration: none; +} +.inline-warning-link:hover { opacity: 1; text-decoration: underline; } + /* Memory summary on deploy page */ .memory-summary { background: var(--bg-card); @@ -1481,11 +1510,7 @@ a.stat-card:hover { letter-spacing: 0; margin-left: .25rem; } -.col-na { - color: var(--text-muted); - font-style: italic; - cursor: help; -} + .snapshot-footer { padding: .75rem .75rem 0; @@ -2343,8 +2368,8 @@ a.stat-card:hover { /* Cross-drive backup card on deploy page */ .deploy-cross-drive { - background: var(--card-bg); - border: 1px solid var(--border); + background: var(--bg-secondary); + border: 1px solid var(--border-color); border-radius: var(--radius); padding: 1.5rem; margin-top: 1rem;