Files
felhom-controller/controller/internal/web/templates/settings_system.html
T
admin cb6f04c8fc D1 Part 3: unified drive view + overlay migration
- storage.html: the registry cards and the separate 'Meghajtók (ügynök
  nézet)' merge into ONE view. Each connected registry card gets an
  #agent-extra-<path> slot; the enrichment JS joins the agent /api/disks
  list on mount path and decorates the matching card in place (role tag
  via i-lock, drive class, durable-id mono line, agent-only
  register/eject/wipe actions). Two extra groups render below:
  'Rendszermeghajtók' (system/backup — read-only, lock tag, NO actions)
  and 'Nem regisztrált meghajtók' (unregistered user-data — register
  action only). Agent-down: one warn note into #agent-warn-note, all
  registry cards still render from server data (graceful degradation).
  The agent-view helpers now emit design-system .tag markup instead of
  .badge (roleTag/classTag/dataTag/regTag/appBackingTag); the 🔒 lock
  emoji is gone (sprite i-lock).
- Overlay migration: every native confirm()/prompt() on the four pages
  routes through a light .confirm-overlay dialog (openDialog; texts
  verbatim) — storage remove forms, netStorageRemove, storageMigrateAll,
  storageDisconnect, storageDecommission (migrate + the type-to-confirm
  anyway branch preserved like-for-like), storageReEnroll; and on the
  system page triggerUpdate + controller/server restart; on the security
  page the two geo Hungary-removal confirms. Scenario F grep: zero
  native confirm/prompt in the four templates.
- Deleted the now-orphaned .badge-lock/.lock-ico CSS (grep-zero first).
- Tests: no-native-confirm scan, agent-down warn-note static assertion;
  integrity gate stays green.
2026-07-02 19:17:19 +02:00

304 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "settings_system"}}
{{template "layout_start" .}}
<div class="page-header">
<h2>Beállítások — Rendszer</h2>
</div>
<!-- Section A: System Configuration (read-only) -->
<div class="settings-card">
<h3>Rendszer konfiguráció</h3>
<p class="settings-card-desc">Az üzemeltető által beállított értékek. Módosításhoz kérd az üzemeltetőt.</p>
<div class="settings-grid">
<div class="settings-row">
<span class="settings-label">Ügyfél azonosító</span>
<span class="settings-value mono">{{.CustomerID}}</span>
</div>
<div class="settings-row">
<span class="settings-label">Ügyfél neve</span>
<span class="settings-value">{{.CustomerName}}</span>
</div>
<div class="settings-row">
<span class="settings-label">Domain</span>
<span class="settings-value mono">{{.CustomerDomain}}</span>
</div>
{{if .GitRepoURL}}
<div class="settings-row">
<span class="settings-label">Alkalmazás sablon forrás</span>
<span class="settings-value mono settings-value-truncate">{{.GitRepoURL}}</span>
</div>
{{end}}
<div class="settings-row">
<span class="settings-label">Sablon szinkronizálás</span>
<span class="settings-value mono">{{.GitSyncInterval}}</span>
</div>
<div class="settings-row">
<span class="settings-label">Biztonsági mentés</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">
<span class="settings-label">Mentés ütemezés</span>
<span class="settings-value mono">{{.DBDumpSchedule}} / {{.ResticSchedule}}</span>
</div>
{{end}}
<div class="settings-row">
<span class="settings-label">Monitoring</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">
<span class="settings-label">Healthchecks URL</span>
<span class="settings-value mono settings-value-truncate">{{if .HealthchecksBase}}{{.HealthchecksBase}}{{else}}{{end}}</span>
</div>
{{end}}
<div class="settings-row">
<span class="settings-label">Hub jelentés</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>
<!-- Section: Version & Update -->
<div class="settings-card">
<h3>Verzió és frissítés</h3>
<div class="settings-grid">
<div class="settings-row">
<span class="settings-label">Jelenlegi verzió</span>
<span class="settings-value mono">{{.Version}}</span>
</div>
{{if .SelfUpdateEnabled}}
{{if .LatestVersion}}
<div class="settings-row">
<span class="settings-label">Legújabb verzió</span>
<span class="settings-value mono">
{{.LatestVersion}}
{{if .UpdateAvailable}}
<span class="state-text-run" style="margin-left:0.5em;">● Frissítés elérhető</span>
{{else}}
<span style="margin-left:0.5em; color:var(--text-3);">— naprakész</span>
{{end}}
</span>
</div>
{{end}}
{{if .LastCheckTime}}
<div class="settings-row">
<span class="settings-label">Utolsó ellenőrzés</span>
<span class="settings-value mono">{{.LastCheckTime}}</span>
</div>
{{end}}
{{if .LastCheckError}}
<div class="settings-row">
<span class="settings-label">Hiba</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-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}}
<div class="settings-row">
<span class="settings-label">Minimális verzió (üzemeltető)</span>
<span class="settings-value mono">
{{.ControllerFloor}}
<span style="margin-left:0.5em; color:#888;">— a rendszer automatikusan erre a verzióra frissít, ha régebbi</span>
</span>
</div>
{{end}}
{{if .UpdateRunning}}
<div class="settings-row">
<span class="settings-label">Állapot</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-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>
{{end}}
<div class="settings-row" style="padding-top: 0.5em;">
<span class="settings-label"></span>
<span class="settings-value">
<button class="btn btn-secondary btn-sm" id="btn-check-update" onclick="checkUpdate()">Frissítés keresése</button>
{{if .UpdateAvailable}}
<button class="btn btn-primary btn-sm" id="btn-trigger-update" onclick="triggerUpdate()" style="margin-left:0.5em;">Frissítés telepítése</button>
{{end}}
<span id="update-status-msg" style="margin-left:0.5em; display:none;"></span>
</span>
</div>
{{end}}
</div>
</div>
<div id="dialog-root"></div>
<script>
// Light overlay dialog (D1) — replaces the native blocking browser dialogs (same texts).
function escText(s){var d=document.createElement('div');d.textContent=String(s==null?'':s);return d.innerHTML;}
function closeDialog(){ var r=document.getElementById('dialog-root'); if(r) r.innerHTML=''; }
function openDialog(opts){
var root=document.getElementById('dialog-root');
if(!root) return;
root.innerHTML='<div class="confirm-overlay" onclick="if(event.target===this)document.getElementById(\'dialog-cancel\').click()"><div class="confirm-box">'
+'<h3>'+escText(opts.title||'Megerősítés')+'</h3>'
+'<p style="white-space:pre-line">'+escText(opts.message||'')+'</p>'
+'<div class="form-actions"><button id="dialog-go" class="btn btn-primary">'+escText(opts.confirmLabel||'Megerősítés')+'</button>'
+'<button type="button" class="btn btn-outline" id="dialog-cancel">Mégsem</button></div>'
+'</div></div>';
document.getElementById('dialog-go').onclick=function(){ closeDialog(); if(opts.onConfirm) opts.onConfirm(); };
document.getElementById('dialog-cancel').onclick=function(){ closeDialog(); if(opts.onCancel) opts.onCancel(); };
}
function checkUpdate() {
var btn = document.getElementById('btn-check-update');
var msg = document.getElementById('update-status-msg');
btn.disabled = true;
btn.textContent = 'Ellenőrzés...';
msg.style.display = 'none';
fetch('/api/selfupdate/check', {method:'POST', headers: csrfHeaders()})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.ok) {
location.reload();
} else {
msg.textContent = data.error || 'Hiba történt';
msg.style.display = 'inline';
btn.disabled = false;
btn.textContent = 'Frissítés keresése';
}
})
.catch(function() {
msg.textContent = 'Kapcsolódási hiba';
msg.style.display = 'inline';
btn.disabled = false;
btn.textContent = 'Frissítés keresése';
});
}
function triggerUpdate() {
openDialog({title:'Vezérlő frissítése', confirmLabel:'Frissítés',
message:'Biztosan frissíti a controllert?\n\nA folyamat alatt a vezérlőpult rövid időre elérhetetlenné válik.',
onConfirm:doTriggerUpdate});
}
function doTriggerUpdate() {
var btn = document.getElementById('btn-trigger-update');
var checkBtn = document.getElementById('btn-check-update');
var msg = document.getElementById('update-status-msg');
btn.disabled = true;
btn.textContent = 'Frissítés...';
if (checkBtn) checkBtn.disabled = true;
msg.textContent = 'Frissítés folyamatban...';
msg.style.display = 'inline';
fetch('/api/selfupdate/update', {method:'POST', headers: csrfHeaders()})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.ok) {
msg.textContent = 'Újraindulás...';
pollUntilBack();
} else {
msg.textContent = data.error || 'Hiba történt';
btn.disabled = false;
btn.textContent = 'Frissítés telepítése';
if (checkBtn) checkBtn.disabled = false;
}
})
.catch(function() {
msg.textContent = 'Kapcsolódási hiba';
pollUntilBack();
});
}
function pollUntilBack() {
var iv = setInterval(function() {
fetch('/api/health')
.then(function(r) {
if (r.ok) {
clearInterval(iv);
location.reload();
}
})
.catch(function() {});
}, 3000);
}
// If an update is already in flight when the page loads (e.g. a floor-driven AUTO-update kicked off by
// the hub, not a button click), surface the same restart-poll panel so the page recovers itself.
{{if .UpdateRunning}}
pollUntilBack();
{{end}}
</script>
<!-- Section: Controller restart (self-serve) — always available (not gated on RetrievalPassword) -->
<div class="settings-card">
<h3>Vezérlő újraindítása</h3>
<p class="settings-card-desc">
Ha a vezérlő hibásan működik, itt biztonságosan újraindíthatja — nem kell az egész szervert újraindítani.
Az alkalmazásai futnak tovább; csak a vezérlő indul újra (néhány másodperc).
</p>
<div id="restart-status"></div>
<button type="button" class="btn btn-outline" id="btn-restart-controller" onclick="restartController()">Vezérlő újraindítása</button>
</div>
<!-- Section: Full server (guest) restart — a deliberate maintenance affordance, sibling to the controller restart -->
<div class="settings-card">
<h3>Kiszolgáló újraindítása</h3>
<p class="settings-card-desc">
Az egész kiszolgáló (szerver) újraindítása. Minden alkalmazás rövid időre leáll, és a vezérlőpult kb. 30 másodpercig nem elérhető. Akkor használja, ha a teljes rendszer újraindítására van szükség — egyébként a fenti „Vezérlő újraindítása” elegendő.
</p>
<div id="server-restart-status"></div>
<button type="button" class="btn btn-outline" id="btn-restart-server" onclick="restartServer()">Kiszolgáló újraindítása</button>
</div>
<script>
function restartController() {
openDialog({title:'Vezérlő újraindítása', confirmLabel:'Újraindítás',
message:'Biztosan újraindítja a vezérlőt? A művelet néhány másodpercig tart, és a felület rövid időre elérhetetlen lesz.',
onConfirm:doRestartController});
}
function doRestartController() {
var btn = document.getElementById('btn-restart-controller');
var status = document.getElementById('restart-status');
btn.disabled = true;
status.innerHTML = '<div class="alert alert-info">Újraindítás folyamatban… újracsatlakozás…</div>';
fetch('/api/selfrestart', { method: 'POST', headers: csrfHeaders() })
.then(function(){ pollRestart(0); })
.catch(function(){ pollRestart(0); }); // connection may drop as the process exits — poll regardless
}
function restartServer() {
openDialog({title:'Kiszolgáló újraindítása', confirmLabel:'Újraindítás',
message:'Biztosan újraindítja a kiszolgálót? Az alkalmazások és a vezérlőpult kb. 30 másodpercre elérhetetlenné válnak.',
onConfirm:doRestartServer});
}
function doRestartServer() {
var btn = document.getElementById('btn-restart-server');
var status = document.getElementById('server-restart-status');
if (btn) btn.disabled = true;
if (status) status.innerHTML = '<div class="alert alert-info">Újraindítás folyamatban… a vezérlőpult néhány másodperc múlva újratölt.</div>';
fetch('/api/server/reboot', { method: 'POST', headers: csrfHeaders() })
.then(function(){ pollRestart(0); })
.catch(function(){ pollRestart(0); }); // the guest reboot drops the connection — poll regardless
}
function pollRestart(attempt) {
if (attempt > 60) { // ~2 min cap — never leave the user on a dead page silently
document.getElementById('restart-status').innerHTML =
'<div class="alert alert-error">Az újraindítás a vártnál tovább tart. Töltse újra az oldalt kézzel.</div>';
return;
}
setTimeout(function(){
fetch('/', { method: 'GET', cache: 'no-store' })
.then(function(r){ if (r.ok) { window.location.reload(); } else { pollRestart(attempt + 1); } })
.catch(function(){ pollRestart(attempt + 1); });
}, 2000);
}
</script>
{{template "layout_end" .}}
{{end}}