D0 Part 2: design system v2 — tokens, meter/tag/metarow, funcmap remap, dashboard + stacks
- style.css: navy token palette (--bg-0/1/2, --line, --text-1/2/3, --blue, --warn, --crit), single 2px radius, all box-shadows and the bg grid overlay removed, fonts via --font-ui/--font-data. - Components: .meter (3px hairline track, blue nominal fill, neutral 70/85 ticks, warn/crit flag), .tag (square 2px state chip + dot, pulse on progress, reduced-motion respected), .metarow (icon + text, no container), .panel/.list/.section-h primitives, boxless .stats with hairline dividers, buttons 2px (danger = crit outline). - funcmap: stateColor -> run/progress/warn/neutral/off (stopped is neutral, NOT red — operator-approved exception-color change), usageColor/tempColor -> nominal/warn/crit (thresholds unchanged); stateLabel Hungarian copy untouched (guarded by test). - layout.html: sprite nav icons (layout-grid/cloud/shield/cpu/wrench/ settings), alert banner emoji -> triangle-alert/info icons. - dashboard.html: meters with disk warn/crit flags (Fogyóban a hely / Kritikusan kevés hely), boxless stats (Leállítva 0 muted, >0 amber), single-panel stack list with 2px state edges, tags instead of badges, icon action buttons. - stacks.html: state tag + metarow rows; catalog keeps its grid. - setup minimalCSS retokened to v2 (drops GitHub-dark hexes). - Tests: §8 truth tables for stateColor/usageColor/tempColor + stateLabel byte-identity guard (red-proven vs pre-change funcmap: stopped->red and 0->green failed as required).
This commit is contained in:
@@ -49,20 +49,29 @@ func (s *Server) templateFuncMap() template.FuncMap {
|
||||
loc := getTimezone()
|
||||
|
||||
return template.FuncMap{
|
||||
// stateColor maps container states to design-system-v2 semantic tokens,
|
||||
// consumed as class suffixes (tag-run, stack-state-run, state-text-run...).
|
||||
// Exception-color principle: a customer-stopped app is neutral, NOT red —
|
||||
// genuine failures surface via unhealthy state + the alert system.
|
||||
"stateColor": func(state stacks.ContainerState) string {
|
||||
switch state {
|
||||
case stacks.StateRunning:
|
||||
return "green"
|
||||
return "run"
|
||||
case stacks.StateStarting, stacks.StateDeploying:
|
||||
return "orange"
|
||||
return "progress"
|
||||
case stacks.StateUnhealthy:
|
||||
return "yellow"
|
||||
case stacks.StateStopped, stacks.StateExited:
|
||||
return "red"
|
||||
return "warn"
|
||||
case stacks.StateRestarting:
|
||||
return "yellow"
|
||||
// a restart loop is a problem, not progress
|
||||
return "warn"
|
||||
case stacks.StateStopped, stacks.StateExited:
|
||||
return "neutral"
|
||||
case stacks.StatePaused:
|
||||
return "neutral"
|
||||
case stacks.StateNotDeployed:
|
||||
return "off"
|
||||
default:
|
||||
return "gray"
|
||||
return "off"
|
||||
}
|
||||
},
|
||||
"stateLabel": func(state stacks.ContainerState) string {
|
||||
@@ -126,14 +135,15 @@ func (s *Server) templateFuncMap() template.FuncMap {
|
||||
"appPageURL": func(slug string) string {
|
||||
return s.cfg.AppPageURL(slug)
|
||||
},
|
||||
// usageColor: capacity meters are blue below 70%, amber 70–85, red ≥85 (v2).
|
||||
"usageColor": func(percent float64) string {
|
||||
if percent >= 85 {
|
||||
return "red"
|
||||
return "crit"
|
||||
}
|
||||
if percent >= 70 {
|
||||
return "yellow"
|
||||
return "warn"
|
||||
}
|
||||
return "green"
|
||||
return "nominal"
|
||||
},
|
||||
"fmtMB": func(mb uint64) string {
|
||||
if mb >= 1024 {
|
||||
@@ -171,14 +181,15 @@ func (s *Server) templateFuncMap() template.FuncMap {
|
||||
}
|
||||
return result
|
||||
},
|
||||
// tempColor: thresholds unchanged; outputs remapped to v2 tokens.
|
||||
"tempColor": func(celsius float64) string {
|
||||
if celsius > 75 {
|
||||
return "red"
|
||||
return "crit"
|
||||
}
|
||||
if celsius >= 60 {
|
||||
return "yellow"
|
||||
return "warn"
|
||||
}
|
||||
return "green"
|
||||
return "nominal"
|
||||
},
|
||||
"fmtTemp": func(celsius float64) string {
|
||||
return fmt.Sprintf("%.0f°C", celsius)
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
||||
)
|
||||
|
||||
// TASK-D0 §8 truth tables. These are the semantic contract of the v2 re-skin:
|
||||
// every class suffix the templates key on comes from these three functions.
|
||||
|
||||
func TestStateColorTruthTable(t *testing.T) {
|
||||
s := &Server{}
|
||||
fm := s.templateFuncMap()
|
||||
stateColor := fm["stateColor"].(func(stacks.ContainerState) string)
|
||||
|
||||
cases := []struct {
|
||||
state stacks.ContainerState
|
||||
want string
|
||||
}{
|
||||
{stacks.StateRunning, "run"},
|
||||
{stacks.StateStarting, "progress"},
|
||||
{stacks.StateDeploying, "progress"},
|
||||
{stacks.StateUnhealthy, "warn"},
|
||||
{stacks.StateRestarting, "warn"}, // a restart loop is a problem, not progress
|
||||
{stacks.StateStopped, "neutral"}, // deliberately NOT red — customer-stopped is not an emergency
|
||||
{stacks.StateExited, "neutral"},
|
||||
{stacks.StatePaused, "neutral"},
|
||||
{stacks.StateNotDeployed, "off"},
|
||||
{stacks.ContainerState("bogus"), "off"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := stateColor(c.state); got != c.want {
|
||||
t.Errorf("stateColor(%q) = %q, want %q", c.state, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUsageColorTruthTable(t *testing.T) {
|
||||
s := &Server{}
|
||||
fm := s.templateFuncMap()
|
||||
usageColor := fm["usageColor"].(func(float64) string)
|
||||
|
||||
cases := []struct {
|
||||
percent float64
|
||||
want string
|
||||
}{
|
||||
{0, "nominal"},
|
||||
{69.9, "nominal"},
|
||||
{70, "warn"},
|
||||
{84.9, "warn"},
|
||||
{85, "crit"},
|
||||
{100, "crit"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := usageColor(c.percent); got != c.want {
|
||||
t.Errorf("usageColor(%v) = %q, want %q", c.percent, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTempColorTruthTable(t *testing.T) {
|
||||
s := &Server{}
|
||||
fm := s.templateFuncMap()
|
||||
tempColor := fm["tempColor"].(func(float64) string)
|
||||
|
||||
// thresholds unchanged from v1: >75 crit, >=60 warn, else nominal
|
||||
cases := []struct {
|
||||
celsius float64
|
||||
want string
|
||||
}{
|
||||
{40, "nominal"},
|
||||
{59.9, "nominal"},
|
||||
{60, "warn"},
|
||||
{75, "warn"},
|
||||
{75.1, "crit"},
|
||||
{90, "crit"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := tempColor(c.celsius); got != c.want {
|
||||
t.Errorf("tempColor(%v) = %q, want %q", c.celsius, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestStateLabelUnchanged guards the Hungarian copy against accidental edits
|
||||
// during the re-skin — labels must stay byte-identical to pre-D0.
|
||||
func TestStateLabelUnchanged(t *testing.T) {
|
||||
s := &Server{}
|
||||
fm := s.templateFuncMap()
|
||||
stateLabel := fm["stateLabel"].(func(stacks.ContainerState) string)
|
||||
|
||||
cases := []struct {
|
||||
state stacks.ContainerState
|
||||
want string
|
||||
}{
|
||||
{stacks.StateRunning, "Fut"},
|
||||
{stacks.StateStarting, "Indulás..."},
|
||||
{stacks.StateDeploying, "Telepítés..."},
|
||||
{stacks.StateUnhealthy, "Nem egészséges"},
|
||||
{stacks.StateStopped, "Leállítva"},
|
||||
{stacks.StateExited, "Leállítva"},
|
||||
{stacks.StateRestarting, "Újraindítás..."},
|
||||
{stacks.StateNotDeployed, "Nincs telepítve"},
|
||||
{stacks.StatePaused, "Szüneteltetve"},
|
||||
{stacks.ContainerState("bogus"), "Ismeretlen"},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := stateLabel(c.state); got != c.want {
|
||||
t.Errorf("stateLabel(%q) = %q, want %q", c.state, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,15 +7,15 @@
|
||||
</div>
|
||||
|
||||
<div class="stats-grid">
|
||||
<a href="/stacks?filter=running" class="stat-card stat-running">
|
||||
<a href="/stacks?filter=running" class="stat-card">
|
||||
<div class="stat-value">{{.RunningCount}}</div>
|
||||
<div class="stat-label">Futó alkalmazás</div>
|
||||
</a>
|
||||
<a href="/stacks?filter=stopped" class="stat-card stat-stopped">
|
||||
<a href="/stacks?filter=stopped" class="stat-card {{if gt .StoppedCount 0}}stat-warn{{else}}stat-zero{{end}}">
|
||||
<div class="stat-value">{{.StoppedCount}}</div>
|
||||
<div class="stat-label">Leállítva</div>
|
||||
</a>
|
||||
<a href="/stacks" class="stat-card stat-total">
|
||||
<a href="/stacks" class="stat-card">
|
||||
<div class="stat-value">{{.TotalCount}}</div>
|
||||
<div class="stat-label">Összes alkalmazás</div>
|
||||
</a>
|
||||
@@ -24,65 +24,66 @@
|
||||
{{if .SystemInfo.TotalMemMB}}
|
||||
<div class="system-info-card">
|
||||
<div class="system-info-items">
|
||||
<div class="system-info-item">
|
||||
<div class="system-info-item meter {{usageColor .SystemInfo.MemPercent}}">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">Memória</span>
|
||||
<span class="system-info-value">{{fmtMB .SystemInfo.UsedMemMB}} / {{fmtMB .SystemInfo.TotalMemMB}} ({{printf "%.0f" .SystemInfo.MemPercent}}%)</span>
|
||||
</div>
|
||||
<div class="system-bar">
|
||||
<div class="system-bar-fill system-bar-{{usageColor .SystemInfo.MemPercent}}" style="width:{{printf "%.0f" .SystemInfo.MemPercent}}%"></div>
|
||||
<div class="meter-track">
|
||||
<div class="meter-fill" style="width:{{printf "%.0f" .SystemInfo.MemPercent}}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="system-info-item">
|
||||
<div class="system-info-item meter {{usageColor .SystemInfo.CPUPercent}}">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">CPU</span>
|
||||
<span class="system-info-value">{{printf "%.0f" .SystemInfo.CPUPercent}}%</span>
|
||||
</div>
|
||||
<div class="system-bar">
|
||||
<div class="system-bar-fill system-bar-{{usageColor .SystemInfo.CPUPercent}}" style="width:{{printf "%.0f" .SystemInfo.CPUPercent}}%"></div>
|
||||
<div class="meter-track">
|
||||
<div class="meter-fill" style="width:{{printf "%.0f" .SystemInfo.CPUPercent}}%"></div>
|
||||
</div>
|
||||
<div class="system-load-avg">Load: {{fmtLoad .SystemInfo.LoadAvg1}} / {{fmtLoad .SystemInfo.LoadAvg5}} / {{fmtLoad .SystemInfo.LoadAvg15}}</div>
|
||||
</div>
|
||||
{{if .SystemInfo.TemperatureCelsius}}
|
||||
<div class="system-info-item system-info-item-compact">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">Hőmérséklet</span>
|
||||
<span class="system-info-value">
|
||||
<span class="temp-dot temp-dot-{{tempColor .SystemInfo.TemperatureCelsius}}"></span>
|
||||
<span class="temp-value-pill temp-pill-{{tempColor .SystemInfo.TemperatureCelsius}}">{{fmtTemp .SystemInfo.TemperatureCelsius}}</span>
|
||||
</span>
|
||||
<span class="system-info-label"><svg class="ico ico-sm"><use href="#i-thermometer"/></svg> Hőmérséklet</span>
|
||||
<span class="system-info-value temp-value state-text-{{tempColor .SystemInfo.TemperatureCelsius}}">{{fmtTemp .SystemInfo.TemperatureCelsius}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="system-info-items" style="margin-top: 1rem;">
|
||||
<div class="system-info-item">
|
||||
{{$duc := usageColor .SystemInfo.DiskPercent}}
|
||||
<div class="system-info-item meter {{$duc}}">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">Rendszer (/)</span>
|
||||
<span class="system-info-value">{{fmtGB .SystemInfo.DiskUsedGB}} / {{fmtGB .SystemInfo.DiskTotalGB}} ({{printf "%.0f" .SystemInfo.DiskPercent}}%)</span>
|
||||
</div>
|
||||
<div class="system-bar">
|
||||
<div class="system-bar-fill system-bar-{{usageColor .SystemInfo.DiskPercent}}" style="width:{{printf "%.0f" .SystemInfo.DiskPercent}}%"></div>
|
||||
<div class="meter-track">
|
||||
<div class="meter-fill" style="width:{{printf "%.0f" .SystemInfo.DiskPercent}}%"></div>
|
||||
</div>
|
||||
{{if eq $duc "warn"}}<div class="meter-flag"><svg class="ico"><use href="#i-triangle-alert"/></svg>Fogyóban a hely</div>{{else if eq $duc "crit"}}<div class="meter-flag"><svg class="ico"><use href="#i-triangle-alert"/></svg>Kritikusan kevés hely</div>{{end}}
|
||||
</div>
|
||||
{{range .StorageBars}}
|
||||
{{if .Disconnected}}
|
||||
<div class="system-info-item storage-disconnected">
|
||||
<div class="system-info-item meter meter-empty storage-disconnected">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">{{.Label}}</span>
|
||||
<span class="system-info-value badge-error" style="font-size:.75rem">Leválasztva</span>
|
||||
<span class="system-info-value">— <span class="state-text-neutral">Leválasztva</span></span>
|
||||
</div>
|
||||
<div class="system-bar"><div class="system-bar-disconnected"></div></div>
|
||||
<div class="meter-track"></div>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="system-info-item">
|
||||
{{$uc := usageColor .Percent}}
|
||||
<div class="system-info-item meter {{$uc}}">
|
||||
<div class="system-info-header">
|
||||
<span class="system-info-label">{{.Label}}</span>
|
||||
<span class="system-info-value">{{fmtGB .UsedGB}} / {{fmtGB .TotalGB}} ({{printf "%.0f" .Percent}}%)</span>
|
||||
</div>
|
||||
<div class="system-bar">
|
||||
<div class="system-bar-fill system-bar-{{usageColor .Percent}}" style="width:{{printf "%.0f" .Percent}}%"></div>
|
||||
<div class="meter-track">
|
||||
<div class="meter-fill" style="width:{{printf "%.0f" .Percent}}%"></div>
|
||||
</div>
|
||||
{{if eq $uc "warn"}}<div class="meter-flag"><svg class="ico"><use href="#i-triangle-alert"/></svg>Fogyóban a hely</div>{{else if eq $uc "crit"}}<div class="meter-flag"><svg class="ico"><use href="#i-triangle-alert"/></svg>Kritikusan kevés hely</div>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -117,7 +118,7 @@
|
||||
<span class="backup-label">Utolsó mentés:</span>
|
||||
<span class="backup-value">
|
||||
{{if .BackupStatus.Success}}
|
||||
<span class="backup-status-ok">{{.BackupStatus.LastRun.Format "2006-01-02 15:04"}}</span>
|
||||
<span>{{.BackupStatus.LastRun.Format "2006-01-02 15:04"}}</span>
|
||||
{{else}}
|
||||
<span class="backup-status-fail">Sikertelen</span>
|
||||
{{end}}
|
||||
@@ -155,27 +156,27 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="stack-actions">
|
||||
<span class="stack-state-label">{{stateLabel .State}}</span>
|
||||
{{if .Orphaned}}<span class="badge badge-orphaned">Elavult</span>{{end}}
|
||||
{{$ms := index $.MissingStorage .Name}}{{if $ms}}<span class="badge badge-missing-storage" title="Az alkalmazás adattárolója nem elérhető. Csatlakoztasd újra a meghajtót, vagy helyezd át az adatokat egy másik tárhelyre.">⚠ Hiányzó tárhely: {{$ms}}</span>{{end}}
|
||||
{{$nw := index $.NetworkWarnings .Name}}{{if $nw}}<span class="badge badge-warn" title="A hálózati tárhely (NAS) jelenleg nem érhető el. Az alkalmazás fut; az adatok elérése a NAS visszatértével helyreáll.">⚠ Hálózati tárhely nem elérhető: {{$nw}}</span>{{end}}
|
||||
{{if and .Deployed (routeUnpublished .State)}}<span class="badge badge-route-unpublished" title="A proxy (Traefik) csak egészséges konténerhez publikál nyilvános útvonalat. Amíg az alkalmazás nem egészséges, az URL 404-et ad, pedig a konténer fut.">⚠ URL nem elérhető</span>{{end}}
|
||||
<span class="tag tag-{{stateColor .State}}"><span class="dot"></span>{{stateLabel .State}}</span>
|
||||
{{if .Orphaned}}<span class="tag tag-warn">Elavult</span>{{end}}
|
||||
{{$ms := index $.MissingStorage .Name}}{{if $ms}}<span class="tag tag-warn" title="Az alkalmazás adattárolója nem elérhető. Csatlakoztasd újra a meghajtót, vagy helyezd át az adatokat egy másik tárhelyre."><svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg>Hiányzó tárhely: {{$ms}}</span>{{end}}
|
||||
{{$nw := index $.NetworkWarnings .Name}}{{if $nw}}<span class="tag tag-warn" title="A hálózati tárhely (NAS) jelenleg nem érhető el. Az alkalmazás fut; az adatok elérése a NAS visszatértével helyreáll."><svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg>Hálózati tárhely nem elérhető: {{$nw}}</span>{{end}}
|
||||
{{if and .Deployed (routeUnpublished .State)}}<span class="tag tag-warn" title="A proxy (Traefik) csak egészséges konténerhez publikál nyilvános útvonalat. Amíg az alkalmazás nem egészséges, az URL 404-et ad, pedig a konténer fut."><svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg>URL nem elérhető</span>{{end}}
|
||||
|
||||
{{if .Protected}}
|
||||
<span class="badge badge-protected">Védett</span>
|
||||
<span class="tag"><svg class="ico ico-sm"><use href="#i-lock"/></svg>Védett</span>
|
||||
{{if isOperational .State}}
|
||||
<button class="btn btn-sm btn-warning" onclick="stackAction(event, '{{.Name}}', 'restart')">↻</button>
|
||||
<button class="btn btn-sm btn-warning" onclick="stackAction(event, '{{.Name}}', 'restart')" title="Újraindítás"><svg class="ico ico-sm"><use href="#i-rotate-cw"/></svg></button>
|
||||
{{end}}
|
||||
{{else if not .Deployed}}
|
||||
<a href="/stacks/{{.Name}}/deploy" class="btn btn-sm btn-primary" onclick="return checkBeforeDeploy(event, '{{.Name}}')">Telepítés</a>
|
||||
{{else}}
|
||||
{{if isOperational .State}}
|
||||
{{$subdomain := index $.Subdomains .Name}}
|
||||
{{if $subdomain}}<a href="https://{{$subdomain}}.{{$.Domain}}{{.Meta.OpenPath}}" target="_blank" class="btn btn-sm btn-outline" onclick="event.stopPropagation()">Megnyitás ↗</a>{{end}}
|
||||
<button class="btn btn-sm btn-warning" onclick="stackAction(event, '{{.Name}}', 'restart')">↻</button>
|
||||
<button class="btn btn-sm btn-danger" onclick="stackAction(event, '{{.Name}}', 'stop')">■</button>
|
||||
{{if $subdomain}}<a href="https://{{$subdomain}}.{{$.Domain}}{{.Meta.OpenPath}}" target="_blank" class="btn btn-sm btn-outline" onclick="event.stopPropagation()">Megnyitás <svg class="ico ico-sm"><use href="#i-external-link"/></svg></a>{{end}}
|
||||
<button class="btn btn-sm btn-warning" onclick="stackAction(event, '{{.Name}}', 'restart')" title="Újraindítás"><svg class="ico ico-sm"><use href="#i-rotate-cw"/></svg></button>
|
||||
<button class="btn btn-sm btn-danger" onclick="stackAction(event, '{{.Name}}', 'stop')" title="Leállítás"><svg class="ico ico-sm"><use href="#i-square"/></svg></button>
|
||||
{{else}}
|
||||
<button class="btn btn-sm btn-success" onclick="stackAction(event, '{{.Name}}', 'start')">▶</button>
|
||||
<button class="btn btn-sm btn-success" onclick="stackAction(event, '{{.Name}}', 'start')" title="Indítás"><svg class="ico ico-sm"><use href="#i-play"/></svg></button>
|
||||
{{if not .Orphaned}}<button class="btn btn-sm btn-danger" onclick="removeStack('{{.Name}}')">Eltávolítás</button>{{end}}
|
||||
{{end}}
|
||||
<a href="/stacks/{{.Name}}/logs" class="btn btn-sm btn-outline">Napló</a>
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
<span class="customer-name">{{.CustomerName}}</span>
|
||||
</div>
|
||||
<ul class="nav-links">
|
||||
<li><a href="/" class="{{if eq .Page "dashboard"}}active{{end}}">Vezérlőpult</a></li>
|
||||
<li><a href="/stacks" class="{{if eq .Page "stacks"}}active{{end}}">Alkalmazások</a></li>
|
||||
<li><a href="/backups" class="{{if eq .Page "backups"}}active{{end}}">Biztonsági mentés</a></li>
|
||||
<li><a href="/monitoring" class="{{if eq .Page "monitoring"}}active{{end}}">Rendszermonitor</a></li>
|
||||
{{if .DebugMode}}<li><a href="/debug" class="{{if eq .Page "debug"}}active{{end}}">🔧 Debug</a></li>{{end}}
|
||||
<li><a href="/" class="{{if eq .Page "dashboard"}}active{{end}}"><svg class="ico"><use href="#i-layout-grid"/></svg>Vezérlőpult</a></li>
|
||||
<li><a href="/stacks" class="{{if eq .Page "stacks"}}active{{end}}"><svg class="ico"><use href="#i-cloud"/></svg>Alkalmazások</a></li>
|
||||
<li><a href="/backups" class="{{if eq .Page "backups"}}active{{end}}"><svg class="ico"><use href="#i-shield"/></svg>Biztonsági mentés</a></li>
|
||||
<li><a href="/monitoring" class="{{if eq .Page "monitoring"}}active{{end}}"><svg class="ico"><use href="#i-cpu"/></svg>Rendszermonitor</a></li>
|
||||
{{if .DebugMode}}<li><a href="/debug" class="{{if eq .Page "debug"}}active{{end}}"><svg class="ico"><use href="#i-wrench"/></svg>Debug</a></li>{{end}}
|
||||
</ul>
|
||||
<div class="sidebar-bottom">
|
||||
<a href="/settings" class="sidebar-settings-link {{if eq .Page "settings"}}active{{end}}">⚙ Beállítások</a>
|
||||
<a href="/settings" class="sidebar-settings-link {{if eq .Page "settings"}}active{{end}}"><svg class="ico"><use href="#i-settings"/></svg>Beállítások</a>
|
||||
<div class="sidebar-footer">
|
||||
<span class="version">{{.Version}}</span>
|
||||
{{if .AuthEnabled}}<a href="/logout" class="logout-link">Kijelentkezés ↗</a>{{end}}
|
||||
@@ -41,7 +41,7 @@
|
||||
{{range .Alerts}}
|
||||
{{if and (not .Inline) (or (not .PageOnly) (pageMatch .PageOnly $.Page))}}
|
||||
<div class="alert-banner alert-banner-{{.Level}}">
|
||||
<span class="alert-icon">{{if eq .Level "error"}}🔴{{else if eq .Level "warning"}}🟡{{else}}ℹ️{{end}}</span>
|
||||
<span class="alert-icon"><svg class="ico">{{if eq .Level "error"}}<use href="#i-triangle-alert"/>{{else if eq .Level "warning"}}<use href="#i-triangle-alert"/>{{else}}<use href="#i-info"/>{{end}}</svg></span>
|
||||
<span class="alert-message">{{.Message}}</span>
|
||||
{{if .Link}}<a href="{{.Link}}" class="alert-link">{{.LinkText}} →</a>{{end}}
|
||||
</div>
|
||||
|
||||
@@ -31,27 +31,27 @@
|
||||
{{$subdomain}}.{{$.Domain}} ↗
|
||||
</a>
|
||||
{{if and .Deployed (routeUnpublished .State)}}
|
||||
<span class="route-unpublished" title="A proxy (Traefik) csak egészséges konténerhez publikál nyilvános útvonalat. Amíg az alkalmazás nem egészséges, az URL nem érhető el (404), pedig a konténer fut.">⚠ URL nem elérhető – útvonal nincs publikálva</span>
|
||||
<span class="route-unpublished" title="A proxy (Traefik) csak egészséges konténerhez publikál nyilvános útvonalat. Amíg az alkalmazás nem egészséges, az URL nem érhető el (404), pedig a konténer fut."><svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg> URL nem elérhető – útvonal nincs publikálva</span>
|
||||
{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<span class="stack-state-badge state-{{stateColor .State}}">{{stateLabel .State}}</span>
|
||||
{{if .Orphaned}}<span class="badge badge-orphaned">Elavult</span>{{end}}
|
||||
{{$ms := index $.MissingStorage .Name}}{{if $ms}}<span class="badge badge-missing-storage" title="Az alkalmazás adattárolója nem elérhető. Csatlakoztasd újra a meghajtót, vagy helyezd át az adatokat.">⚠ Hiányzó tárhely: {{$ms}}</span>{{end}}
|
||||
{{$nw := index $.NetworkWarnings .Name}}{{if $nw}}<span class="badge badge-warn" title="A hálózati tárhely (NAS) jelenleg nem érhető el. Az alkalmazás fut; az adatok elérése a NAS visszatértével helyreáll.">⚠ Hálózati tárhely nem elérhető: {{$nw}}</span>{{end}}
|
||||
<span class="tag tag-{{stateColor .State}}"><span class="dot"></span>{{stateLabel .State}}</span>
|
||||
{{if .Orphaned}}<span class="tag tag-warn">Elavult</span>{{end}}
|
||||
{{$ms := index $.MissingStorage .Name}}{{if $ms}}<span class="tag tag-warn" title="Az alkalmazás adattárolója nem elérhető. Csatlakoztasd újra a meghajtót, vagy helyezd át az adatokat."><svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg>Hiányzó tárhely: {{$ms}}</span>{{end}}
|
||||
{{$nw := index $.NetworkWarnings .Name}}{{if $nw}}<span class="tag tag-warn" title="A hálózati tárhely (NAS) jelenleg nem érhető el. Az alkalmazás fut; az adatok elérése a NAS visszatértével helyreáll."><svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg>Hálózati tárhely nem elérhető: {{$nw}}</span>{{end}}
|
||||
</div>
|
||||
|
||||
{{if .Meta.Description}}
|
||||
<p class="stack-detail-desc">{{.Meta.Description}}</p>
|
||||
{{end}}
|
||||
|
||||
<div class="stack-meta-badges">
|
||||
{{if .Meta.Resources.MemRequest}}<span class="meta-badge">~{{.Meta.Resources.MemRequest}}</span>{{end}}
|
||||
{{if .Meta.Resources.PiCompatible}}<span class="meta-badge meta-badge-ok">Pi kompatibilis</span>{{end}}
|
||||
{{if .Meta.Resources.NeedsHDD}}<span class="meta-badge">HDD szükséges</span>{{end}}
|
||||
{{if .Meta.Resources.HungarianUI}}<span class="meta-badge meta-badge-ok">Magyar felület</span>{{end}}
|
||||
{{if and .Deployed (index $.StorageLabels .Name)}}<span class="meta-badge meta-badge-storage" title="Adattároló: {{index $.StorageLabels .Name}}">💾 {{index $.StorageLabels .Name}}</span>{{end}}
|
||||
<div class="metarows">
|
||||
{{if .Meta.Resources.MemRequest}}<span class="metarow"><svg class="ico"><use href="#i-memory-stick"/></svg><span class="mono">~{{.Meta.Resources.MemRequest}}</span></span>{{end}}
|
||||
{{if .Meta.Resources.PiCompatible}}<span class="metarow"><svg class="ico"><use href="#i-check"/></svg>Pi kompatibilis</span>{{end}}
|
||||
{{if .Meta.Resources.NeedsHDD}}<span class="metarow"><svg class="ico"><use href="#i-hard-drive"/></svg>HDD szükséges</span>{{end}}
|
||||
{{if .Meta.Resources.HungarianUI}}<span class="metarow"><svg class="ico"><use href="#i-check"/></svg>Magyar felület</span>{{end}}
|
||||
{{if and .Deployed (index $.StorageLabels .Name)}}<span class="metarow" title="Adattároló: {{index $.StorageLabels .Name}}"><svg class="ico"><use href="#i-hard-drive"/></svg>{{index $.StorageLabels .Name}}</span>{{end}}
|
||||
</div>
|
||||
|
||||
{{if .Containers}}
|
||||
@@ -67,7 +67,7 @@
|
||||
|
||||
<div class="stack-detail-actions">
|
||||
{{if .Protected}}
|
||||
<span class="badge badge-protected">Védett rendszerkomponens</span>
|
||||
<span class="tag"><svg class="ico ico-sm"><use href="#i-lock"/></svg>Védett rendszerkomponens</span>
|
||||
{{if isOperational .State}}
|
||||
<button class="btn btn-warning" onclick="stackAction(event, '{{.Name}}', 'restart')">Újraindítás</button>
|
||||
{{end}}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user