D0 Part 4: settings visual pass + remaining pages; grep gate zero

- settings.html: Aktív/Inaktív rows -> run-blue check / neutral gray
  (Inaktív no longer red), update states -> run/crit/progress with
  sprite check/x/spinner, pencil + cancel buttons -> icons, storage
  badges -> tags, host-disk bar + JS drive capBar -> meters
  (usageColorClass -> nominal/warn/crit), state-text-* consumers on the
  new suffixes incl. JS-built class names.
- debug.html, app_info.html, storage_init/attach.html, logs.html:
  emoji -> sprite icons or plain text in templates AND JS strings.
- catchall.html (standalone, no sprite): v2 token sweep of its inline
  style, status emoji -> inline SVGs; a stopped app renders neutral,
  not red.
- login.html: two-tone H1 (last word blue-bright).
- setup_hub_versions.html: stale var(--border,#30363d) fallback -> v2.
- Test Group F grep gate: all 34 banned patterns at ZERO across
  internal/web + internal/setup; Scenario E test now asserts the
  '--bg-0: #0A1220' token literal.
This commit is contained in:
2026-07-02 14:38:51 +02:00
parent f100cef842
commit 7df061c00f
13 changed files with 75 additions and 60 deletions
+27 -26
View File
@@ -34,7 +34,7 @@
</div>
<div class="settings-row">
<span class="settings-label">Biztonsági mentés</span>
<span class="settings-value">{{if .BackupEnabled}}<span class="state-text-green"> Aktív</span>{{else}}<span class="state-text-red">Inaktív</span>{{end}}</span>
<span class="settings-value">{{if .BackupEnabled}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> Aktív</span>{{else}}<span class="state-text-neutral">Inaktív</span>{{end}}</span>
</div>
{{if .BackupEnabled}}
<div class="settings-row">
@@ -44,7 +44,7 @@
{{end}}
<div class="settings-row">
<span class="settings-label">Monitoring</span>
<span class="settings-value">{{if .MonitoringEnabled}}<span class="state-text-green"> Aktív</span>{{else}}<span class="state-text-red">Inaktív</span>{{end}}</span>
<span class="settings-value">{{if .MonitoringEnabled}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> Aktív</span>{{else}}<span class="state-text-neutral">Inaktív</span>{{end}}</span>
</div>
{{if .MonitoringEnabled}}
<div class="settings-row">
@@ -54,7 +54,7 @@
{{end}}
<div class="settings-row">
<span class="settings-label">Hub jelentés</span>
<span class="settings-value">{{if .HubEnabled}}<span class="state-text-green"> Aktív</span>{{else}}{{end}}</span>
<span class="settings-value">{{if .HubEnabled}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> Aktív</span>{{else}}{{end}}</span>
</div>
</div>
</div>
@@ -74,9 +74,9 @@
<span class="settings-value mono">
{{.LatestVersion}}
{{if .UpdateAvailable}}
<span class="state-text-green" style="margin-left:0.5em;">● Frissítés elérhető</span>
<span class="state-text-run" style="margin-left:0.5em;">● Frissítés elérhető</span>
{{else}}
<span style="margin-left:0.5em; color:#888;">— naprakész</span>
<span style="margin-left:0.5em; color:var(--text-3);">— naprakész</span>
{{end}}
</span>
</div>
@@ -90,13 +90,13 @@
{{if .LastCheckError}}
<div class="settings-row">
<span class="settings-label">Hiba</span>
<span class="settings-value state-text-red">{{.LastCheckError}}</span>
<span class="settings-value state-text-crit">{{.LastCheckError}}</span>
</div>
{{end}}
<div class="settings-row">
<span class="settings-label">Automatikus frissítés</span>
<span class="settings-value">
{{if .AutoUpdateEnabled}}<span class="state-text-green"> Aktív</span> <span class="mono">({{.AutoUpdateTime}})</span>{{else}}{{end}}
{{if .AutoUpdateEnabled}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> Aktív</span> <span class="mono">({{.AutoUpdateTime}})</span>{{else}}{{end}}
</span>
</div>
{{if .ControllerFloor}}
@@ -111,16 +111,16 @@
{{if .UpdateRunning}}
<div class="settings-row">
<span class="settings-label">Állapot</span>
<span class="settings-value state-text-yellow" id="auto-update-status"> Frissítés folyamatban — a vezérlő hamarosan újraindul…</span>
<span class="settings-value state-text-progress" id="auto-update-status"><svg class="ico ico-sm ico-spin"><use href="#i-rotate-cw"/></svg> Frissítés folyamatban — a vezérlő hamarosan újraindul…</span>
</div>
{{end}}
{{with .LastUpdateState}}
<div class="settings-row">
<span class="settings-label">Utolsó frissítés</span>
<span class="settings-value">
{{if eq .Status "success"}}<span class="state-text-green"> Sikeres</span> ({{.PreviousVersion}} → {{.TargetVersion}})
{{else if eq .Status "failed"}}<span class="state-text-red"> Sikertelen</span> — {{.Error}}
{{else if eq .Status "pending"}}<span class="state-text-yellow"> Folyamatban</span>
{{if eq .Status "success"}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> Sikeres</span> ({{.PreviousVersion}} → {{.TargetVersion}})
{{else if eq .Status "failed"}}<span class="state-text-crit"><svg class="ico ico-sm"><use href="#i-x"/></svg> Sikertelen</span> — {{.Error}}
{{else if eq .Status "pending"}}<span class="state-text-progress"><svg class="ico ico-sm ico-spin"><use href="#i-rotate-cw"/></svg> Folyamatban</span>
{{end}}
</span>
</div>
@@ -231,7 +231,7 @@ pollUntilBack();
<div class="storage-path-info">
<div class="storage-path-label-wrap" id="label-wrap-{{.Path}}">
<span class="storage-path-label" id="label-display-{{.Path}}">{{.Label}}</span>
{{if not (or .Disconnected .Decommissioned)}}<button class="btn btn-xs btn-ghost" onclick="editStorageLabel('{{.Path}}', '{{.Label}}')" title="Átnevezés">✏️</button>{{end}}
{{if not (or .Disconnected .Decommissioned)}}<button class="btn btn-xs btn-ghost" onclick="editStorageLabel('{{.Path}}', '{{.Label}}')" title="Átnevezés"><svg class="ico ico-sm"><use href="#i-pencil"/></svg></button>{{end}}
</div>
<span class="storage-path-path mono">{{.Path}}</span>
</div>
@@ -239,10 +239,10 @@ pollUntilBack();
{{if .Disconnected}}
<span class="badge badge-error">Leválasztva</span>
{{else if .Decommissioned}}
<span class="badge state-gray">Kiváltva</span>
<span class="tag tag-off"><span class="dot"></span>Kiváltva</span>
{{else}}
{{if .IsDefault}}<span class="badge state-green">Alapértelmezett</span>{{end}}
{{if .Schedulable}}<span class="badge" style="background:rgba(0,136,204,0.15);color:var(--blue-bright)">Aktív</span>{{else}}<span class="badge state-gray">Inaktív</span>{{end}}
{{if .IsDefault}}<span class="tag">Alapértelmezett</span>{{end}}
{{if .Schedulable}}<span class="tag tag-run"><span class="dot"></span>Aktív</span>{{else}}<span class="tag tag-off"><span class="dot"></span>Inaktív</span>{{end}}
{{if .IsUSB}}<span class="badge" style="background:rgba(255,165,0,0.15);color:var(--warn)">USB</span>{{end}}
{{if not .IsMounted}}<span class="badge badge-warn">Rendszermeghajtón</span>{{end}}
{{end}}
@@ -283,9 +283,10 @@ pollUntilBack();
<div class="system-info-header">
<span class="system-info-value">{{.DiskInfo.UsedHuman}} / {{.DiskInfo.TotalHuman}}</span>
</div>
<div class="system-bar">
<div class="system-bar-fill {{if ge .DiskInfo.UsedPercent 90.0}}system-bar-red{{else if ge .DiskInfo.UsedPercent 70.0}}system-bar-yellow{{else}}system-bar-green{{end}}"
style="width:{{printf "%.0f" .DiskInfo.UsedPercent}}%"></div>
<div class="meter {{if ge .DiskInfo.UsedPercent 90.0}}crit{{else if ge .DiskInfo.UsedPercent 70.0}}warn{{else}}nominal{{end}}">
<div class="meter-track">
<div class="meter-fill" style="width:{{printf "%.0f" .DiskInfo.UsedPercent}}%"></div>
</div>
</div>
</div>
{{end}}
@@ -458,7 +459,7 @@ pollUntilBack();
msg.textContent = 'Csatlakoztatás folyamatban…';
fetch('/api/storage/netstorage/add',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify(body)})
.then(function(r){return r.json();}).then(function(d){
if(d.ok){ msg.textContent='Sikeres'; setTimeout(function(){location.reload();},900); }
if(d.ok){ msg.textContent='Sikeres'; setTimeout(function(){location.reload();},900); }
else { msg.textContent='Hiba: '+(d.error||'ismeretlen'); }
}).catch(function(e){ msg.textContent='Hiba: '+e; });
}
@@ -494,7 +495,7 @@ pollUntilBack();
var job=d.data&&d.data.job;
if(!job){ if(body) body.textContent='Nincs folyamatban migráció.'; return; }
if(body) body.innerHTML=migRender(job);
if(job.phase==='done'){ if(body) body.innerHTML+='<br><strong>Kész</strong>'; setTimeout(function(){location.reload();},1500); return; }
if(job.phase==='done'){ if(body) body.innerHTML+='<br><strong>Kész</strong>'; setTimeout(function(){location.reload();},1500); return; }
if(job.phase==='aborted'){ if(body) body.innerHTML+='<br><strong style="color:var(--danger,#c0392b)">Megszakadt: '+(job.error||'')+'</strong><br>A forrás adatai érintetlenek.'; return; }
setTimeout(tick,1500);
}).catch(function(){ setTimeout(tick,2000); });
@@ -539,7 +540,7 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
(function(){
function esc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c];}); }
function hum(b){ if(!b||b<=0) return ''; var u=['B','KB','MB','GB','TB'],i=0,v=b; while(v>=1024&&i<u.length-1){v/=1024;i++;} return (v>=10||i===0?Math.round(v):v.toFixed(1))+' '+u[i]; }
function usageColorClass(p){ if(p>=85) return 'system-bar-red'; if(p>=70) return 'system-bar-yellow'; return 'system-bar-green'; }
function usageColorClass(p){ if(p>=85) return 'crit'; if(p>=70) return 'warn'; return 'nominal'; }
function classBadge(d){
if(d.class==='fast') return '<span class="badge badge-ok">gyors</span>';
if(d.class==='slow') return '<span class="badge badge-muted">lassú</span>';
@@ -582,7 +583,7 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
if(!d.total_bytes || d.total_bytes<=0) return '';
var pct = d.used_fraction ? d.used_fraction*100 : (d.used_bytes/d.total_bytes*100);
pct = Math.max(0, Math.min(100, pct));
return '<div class="drive-cap"><div class="system-bar"><div class="system-bar-fill '+usageColorClass(pct)+'" style="width:'+pct.toFixed(1)+'%"></div></div>'
return '<div class="drive-cap meter '+usageColorClass(pct)+'"><div class="meter-track"><div class="meter-fill" style="width:'+pct.toFixed(1)+'%"></div></div>'
+'<div class="drive-cap-label">'+hum(d.used_bytes)+' / '+hum(d.total_bytes)+' ('+pct.toFixed(0)+'%)</div></div>';
}
function actions(d, registered){
@@ -797,7 +798,7 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
<button class="btn btn-sm btn-outline" onclick="triggerGeoSync()">Kézi szinkronizálás</button>
<span id="geo-sync-status" class="form-hint">
{{if .GeoLastSync}}Utolsó szinkronizálás: {{.GeoLastSync}}{{end}}
{{if .GeoLastError}} <span class="state-text-red">{{.GeoLastError}}</span>{{end}}
{{if .GeoLastError}} <span class="state-text-crit">{{.GeoLastError}}</span>{{end}}
</span>
</div>
</div>
@@ -1054,7 +1055,7 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
var sync = d.data.last_sync || '';
var err = d.data.last_sync_error || '';
status.innerHTML = sync ? ('Utolsó: ' + sync.substring(0,19).replace('T',' ')) : '';
if (err) status.innerHTML += ' <span class="state-text-red">' + escHtml(err) + '</span>';
if (err) status.innerHTML += ' <span class="state-text-crit">' + escHtml(err) + '</span>';
}
});
}, 5000);
@@ -1332,7 +1333,7 @@ function editStorageLabel(path, currentLabel) {
'<input type="hidden" name="storage_path" value="' + path + '">' +
'<input type="text" name="storage_label" class="form-control" value="' + currentLabel.replace(/"/g, '&quot;') + '" style="width:200px;padding:.3rem .5rem;font-size:.9rem" maxlength="50">' +
'<button type="submit" class="btn btn-xs btn-primary">OK</button>' +
'<button type="button" class="btn btn-xs btn-outline" onclick="cancelEditLabel(\'' + path + '\', \'' + currentLabel.replace(/'/g, "\\'") + '\')"></button>' +
'<button type="button" class="btn btn-xs btn-outline" onclick="cancelEditLabel(\'' + path + '\', \'' + currentLabel.replace(/'/g, "\\'") + '\')">&#215;</button>' +
'</form>';
wrap.querySelector('input[name=storage_label]').focus();
}
@@ -1439,7 +1440,7 @@ function cancelEditLabel(path, label) {
var btn = document.createElement('button');
btn.className = 'btn btn-xs btn-ghost';
btn.setAttribute('title', 'Átnevezés');
btn.textContent = '✏️';
btn.innerHTML = '<svg class="ico ico-sm"><use href="#i-pencil"/></svg>';
btn.addEventListener('click', function() { editStorageLabel(path, label); });
wrap.appendChild(span);
wrap.appendChild(document.createTextNode(' '));