9cf13a3add
gates / gates (push) Successful in 24s
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
442 lines
22 KiB
HTML
442 lines
22 KiB
HTML
{{define "settings_system"}}
|
||
{{template "layout_start" .}}
|
||
|
||
<div class="page-header">
|
||
<h2>{{T "settings_system.beallitasok_rendszer"}}</h2>
|
||
</div>
|
||
|
||
<!-- Section A: System Configuration (read-only) -->
|
||
<div class="settings-card">
|
||
<h3>{{T "settings_system.rendszer_konfiguracio"}}</h3>
|
||
<p class="settings-card-desc">{{T "settings_system.az_uzemelteto_altal_beallitott_ertekek"}}</p>
|
||
<div class="settings-grid">
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "common.ugyfel_azonosito"}}</span>
|
||
<span class="settings-value mono">{{.CustomerID}}</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.ugyfel_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">{{T "settings_system.alkalmazas_sablon_forras"}}</span>
|
||
<span class="settings-value mono settings-value-truncate">{{.GitRepoURL}}</span>
|
||
</div>
|
||
{{end}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.sablon_szinkronizalas"}}</span>
|
||
<span class="settings-value mono">{{.GitSyncInterval}}</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.biztonsagi_mentes"}}</span>
|
||
<span class="settings-value">{{if .BackupEnabled}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> {{T "settings_system.aktiv"}}</span>{{else}}<span class="state-text-neutral">{{T "settings_system.inaktiv"}}</span>{{end}}</span>
|
||
</div>
|
||
{{if .BackupEnabled}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.mentes_utemezes"}}</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> {{T "settings_system.aktiv"}}</span>{{else}}<span class="state-text-neutral">{{T "settings_system.inaktiv"}}</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">{{T "settings_system.hub_jelentes"}}</span>
|
||
<span class="settings-value">{{if .HubEnabled}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> {{T "settings_system.aktiv"}}</span>{{else}}–{{end}}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section: Version & Update -->
|
||
<div class="settings-card">
|
||
<h3>{{T "settings_system.verzio_es_frissites"}}</h3>
|
||
<div class="settings-grid">
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.jelenlegi_verzio"}}</span>
|
||
<span class="settings-value mono">{{.Version}}</span>
|
||
</div>
|
||
{{if .SelfUpdateEnabled}}
|
||
{{if .LatestVersion}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.legujabb_verzio"}}</span>
|
||
<span class="settings-value mono">
|
||
{{.LatestVersion}}
|
||
{{if .UpdateAvailable}}
|
||
<span class="state-text-run" style="margin-left:0.5em;">{{T "settings_system.frissites_elerheto"}}</span>
|
||
{{else}}
|
||
<span style="margin-left:0.5em; color:var(--text-3);">{{T "settings_system.naprakesz"}}</span>
|
||
{{end}}
|
||
</span>
|
||
</div>
|
||
{{end}}
|
||
{{if .LastCheckTime}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.utolso_ellenorzes"}}</span>
|
||
<span class="settings-value mono">{{.LastCheckTime}}</span>
|
||
</div>
|
||
{{end}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">Registry</span>
|
||
<span class="settings-value">{{if .RegistryAnonymous}}{{T "settings_system.nyilvanos_hitelesites_nelkul"}}{{else}}{{T "settings_system.hitelesitett"}}{{end}}</span>
|
||
</div>
|
||
{{if .LastCheckError}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "common.hiba"}}</span>
|
||
<span class="settings-value state-text-crit">{{.LastCheckError}}</span>
|
||
</div>
|
||
{{end}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.automatikus_frissites"}}</span>
|
||
<span class="settings-value">
|
||
{{if .AutoUpdateEnabled}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> {{T "settings_system.aktiv"}}</span> <span class="mono">({{.AutoUpdateTime}})</span>{{else}}–{{end}}
|
||
</span>
|
||
</div>
|
||
{{if .ControllerFloor}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.minimalis_verzio_uzemelteto"}}</span>
|
||
<span class="settings-value mono">
|
||
{{.ControllerFloor}}
|
||
<span style="margin-left:0.5em; color:#888;">{{T "settings_system.a_rendszer_automatikusan_erre_a"}}</span>
|
||
</span>
|
||
</div>
|
||
{{end}}
|
||
{{if .UpdateRunning}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.allapot"}}</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> {{T "settings_system.frissites_folyamatban_a_vezerlo_hamarosa"}}</span>
|
||
</div>
|
||
{{end}}
|
||
{{with .LastUpdateState}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.utolso_frissites"}}</span>
|
||
<span class="settings-value">
|
||
{{if eq .Status "success"}}<span class="state-text-run"><svg class="ico ico-sm"><use href="#i-check"/></svg> {{T "settings_system.sikeres"}}</span> ({{.PreviousVersion}} → {{.TargetVersion}})
|
||
{{else if eq .Status "failed"}}<span class="state-text-crit"><svg class="ico ico-sm"><use href="#i-x"/></svg> {{T "settings_system.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> {{T "settings_system.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()">{{T "settings_system.frissites_keresese"}}</button>
|
||
{{if .UpdateAvailable}}
|
||
<button class="btn btn-primary btn-sm" id="btn-trigger-update" onclick="triggerUpdate()" style="margin-left:0.5em;">{{T "settings_system.frissites_telepitese"}}</button>
|
||
{{end}}
|
||
<span id="update-status-msg" style="margin-left:0.5em; display:none;"></span>
|
||
</span>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Section: Automatic app updates (v0.271.0, `09` §3 decision 12) — the per-box switch, ON by default. -->
|
||
<div class="settings-card" id="app-update">
|
||
<h3>{{T "settings_system.app_update_title"}}</h3>
|
||
<p class="settings-card-desc">{{T "settings_system.app_update_desc"}}</p>
|
||
{{if .AppUpdateSuccess}}<div class="alert alert-info">{{.AppUpdateSuccess}}</div>{{end}}
|
||
{{if .AppUpdateError}}<div class="alert alert-error">{{.AppUpdateError}}</div>{{end}}
|
||
<form method="POST" action="/settings/app-update">
|
||
{{.CSRFField}}
|
||
<div class="form-group">
|
||
<label style="display:flex;align-items:center;gap:.5rem">
|
||
<input type="checkbox" name="app_update_unattended" value="on" {{if .AppUpdateUnattended}}checked{{end}} data-app-update-unattended="{{.AppUpdateUnattended}}">
|
||
{{T "settings_system.app_update_toggle"}}
|
||
</label>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button type="submit" class="btn btn-primary">{{T "settings_system.app_update_save"}}</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
|
||
<!-- Section: Network (R-66) — the box's own address. Every value is live-computed per render and
|
||
stored NOWHERE (S-5: a DHCP lease persisted anywhere eventually misdirects people); a missing
|
||
value renders „—" because an address-less row beats a wrong address. -->
|
||
<div class="settings-card">
|
||
<h3>{{T "settings_system.halozat"}}</h3>
|
||
<div class="settings-grid">
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.helyi_cim_lan"}}</span>
|
||
<span class="settings-value mono">{{if .NetLANAddress}}{{.NetLANAddress}}{{else}}— <span style="color:var(--text-3);">{{T "settings_system.nem_allapithato_meg"}}</span>{{end}}</span>
|
||
</div>
|
||
{{if .NetSMBName}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.halozati_nev"}}</span>
|
||
<span class="settings-value mono">\\{{.NetSMBName}}</span>
|
||
</div>
|
||
{{end}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.atjaro"}}</span>
|
||
<span class="settings-value mono">{{if .NetGateway}}{{.NetGateway}}{{else}}— <span style="color:var(--text-3);">{{T "settings_system.nem_allapithato_meg"}}</span>{{end}}</span>
|
||
</div>
|
||
</div>
|
||
<p class="settings-card-desc" style="margin-top:0.5em;">{{T "settings_system.ezek_az_ertekek_a_helyi"}}</p>
|
||
</div>
|
||
|
||
<div class="settings-card">
|
||
<h3>{{T "settings_system.szerver_memoria_ram"}}</h3>
|
||
{{if .MemorySupported}}
|
||
{{if .MemoryReachable}}
|
||
<div class="settings-grid">
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.jelenlegi_memoria"}}</span>
|
||
<span class="settings-value mono">{{.MemoryAllocatedMB}} MB</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.felhasznalt"}}</span>
|
||
<span class="settings-value mono">{{.MemoryUsageMB}} MB</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.megengedett_tartomany"}}</span>
|
||
<span class="settings-value mono">{{.MemoryMinMB}} MB – {{.MemoryMaxMB}} MB</span>
|
||
</div>
|
||
<div class="settings-row" style="padding-top: 0.5em;">
|
||
<span class="settings-label">{{T "settings_system.uj_meret_mb"}}</span>
|
||
<span class="settings-value">
|
||
<input type="number" id="mem-input" class="input mono" style="width:8em;"
|
||
value="{{.MemoryAllocatedMB}}" min="{{.MemoryMinMB}}" max="{{.MemoryMaxMB}}" step="256"
|
||
data-current="{{.MemoryAllocatedMB}}">
|
||
<button class="btn btn-primary btn-sm" id="btn-mem-resize" onclick="resizeMemory()" style="margin-left:0.5em;">{{T "settings_system.atmeretezes"}}</button>
|
||
<span id="mem-status-msg" style="margin-left:0.5em; display:none;"></span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
{{else}}
|
||
<div class="settings-grid">
|
||
<div class="settings-row">
|
||
<span class="settings-label">{{T "settings_system.jelenlegi_memoria"}}</span>
|
||
<span class="settings-value mono">{{if .MemoryProcMB}}{{.MemoryProcMB}} MB{{else}}n/a{{end}}</span>
|
||
</div>
|
||
</div>
|
||
<p class="settings-card-desc">{{T "settings_system.a_kiszolgalo_ugynok_jelenleg_nem"}}</p>
|
||
{{end}}
|
||
{{else}}
|
||
<p class="settings-card-desc">{{T "settings_system.a_memoria_atmeretezesehez_a_kiszolgalo"}}</p>
|
||
{{end}}
|
||
</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||'{{T "settings_system.megerosites"}}')+'</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||'{{T "settings_system.megerosites"}}')+'</button>'
|
||
+'<button type="button" class="btn btn-outline" id="dialog-cancel">{{T "common.megsem"}}</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 = '{{T "settings_system.ellenorzes"}}';
|
||
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 || '{{T "common.hiba_tortent"}}';
|
||
msg.style.display = 'inline';
|
||
btn.disabled = false;
|
||
btn.textContent = '{{T "settings_system.frissites_keresese"}}';
|
||
}
|
||
})
|
||
.catch(function() {
|
||
msg.textContent = '{{T "settings_system.kapcsolodasi_hiba"}}';
|
||
msg.style.display = 'inline';
|
||
btn.disabled = false;
|
||
btn.textContent = '{{T "settings_system.frissites_keresese"}}';
|
||
});
|
||
}
|
||
|
||
function triggerUpdate() {
|
||
openDialog({title:'{{T "settings_system.vezerlo_frissitese"}}', confirmLabel:'{{T "settings_system.frissites"}}',
|
||
message:'{{T "settings_system.biztosan_frissiti_a_controllert_n"}}',
|
||
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 = '{{T "settings_system.frissites_2"}}';
|
||
if (checkBtn) checkBtn.disabled = true;
|
||
msg.textContent = '{{T "settings_system.frissites_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 = '{{T "settings_system.ujraindulas"}}';
|
||
pollUntilBack();
|
||
} else {
|
||
msg.textContent = data.error || '{{T "common.hiba_tortent"}}';
|
||
btn.disabled = false;
|
||
btn.textContent = '{{T "settings_system.frissites_telepitese"}}';
|
||
if (checkBtn) checkBtn.disabled = false;
|
||
}
|
||
})
|
||
.catch(function() {
|
||
msg.textContent = '{{T "settings_system.kapcsolodasi_hiba"}}';
|
||
pollUntilBack();
|
||
});
|
||
}
|
||
|
||
function resizeMemory() {
|
||
var input = document.getElementById('mem-input');
|
||
var target = parseInt(input.value, 10);
|
||
var current = parseInt(input.getAttribute('data-current'), 10);
|
||
if (isNaN(target) || target <= 0) {
|
||
showMemMsg('{{T "settings_system.ervenytelen_memoria_ertek"}}', true);
|
||
return;
|
||
}
|
||
if (target < current) {
|
||
openDialog({title:'{{T "settings_system.memoria_csokkentese"}}', confirmLabel:'{{T "settings_system.csokkentes"}}',
|
||
message:'{{T "settings_system.a_memoria_csokkentese_hatassal_lehet"}}',
|
||
onConfirm:function(){ doResizeMemory(target); }});
|
||
return;
|
||
}
|
||
doResizeMemory(target);
|
||
}
|
||
function doResizeMemory(target) {
|
||
var btn = document.getElementById('btn-mem-resize');
|
||
btn.disabled = true;
|
||
btn.textContent = '{{T "settings_system.atmeretezes_2"}}';
|
||
fetch('/api/system/memory/resize', {
|
||
method:'POST', headers: Object.assign({'Content-Type':'application/json'}, csrfHeaders()),
|
||
body: JSON.stringify({memory_mb: target})
|
||
})
|
||
.then(function(r) { return r.json(); })
|
||
.then(function(data) {
|
||
if (data.ok) {
|
||
showMemMsg(data.error || data.message || '{{T "settings_system.kesz"}}', false);
|
||
setTimeout(function(){ location.reload(); }, 1200);
|
||
} else {
|
||
showMemMsg(data.error || '{{T "settings_system.a_muvelet_nem_sikerult"}}', true);
|
||
btn.disabled = false;
|
||
btn.textContent = '{{T "settings_system.atmeretezes"}}';
|
||
}
|
||
})
|
||
.catch(function() {
|
||
showMemMsg('{{T "settings_system.kapcsolodasi_hiba"}}', true);
|
||
btn.disabled = false;
|
||
btn.textContent = '{{T "settings_system.atmeretezes"}}';
|
||
});
|
||
}
|
||
function showMemMsg(text, isErr) {
|
||
var msg = document.getElementById('mem-status-msg');
|
||
if (!msg) return;
|
||
msg.textContent = text;
|
||
msg.style.color = isErr ? 'var(--danger, #c0392b)' : 'var(--text-2)';
|
||
msg.style.display = 'inline';
|
||
}
|
||
|
||
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>{{T "settings_system.vezerlo_ujrainditasa"}}</h3>
|
||
<p class="settings-card-desc">
|
||
{{T "settings_system.ha_a_vezerlo_hibasan_mukodik"}}
|
||
</p>
|
||
<div id="restart-status"></div>
|
||
<button type="button" class="btn btn-outline" id="btn-restart-controller" onclick="restartController()">{{T "settings_system.vezerlo_ujrainditasa"}}</button>
|
||
</div>
|
||
|
||
<!-- Section: Full server (guest) restart — a deliberate maintenance affordance, sibling to the controller restart -->
|
||
<div class="settings-card">
|
||
<h3>{{T "settings_system.kiszolgalo_ujrainditasa"}}</h3>
|
||
<p class="settings-card-desc">
|
||
{{T "settings_system.az_egesz_kiszolgalo_szerver_ujrainditasa"}}
|
||
</p>
|
||
<div id="server-restart-status"></div>
|
||
<button type="button" class="btn btn-outline" id="btn-restart-server" onclick="restartServer()">{{T "settings_system.kiszolgalo_ujrainditasa"}}</button>
|
||
</div>
|
||
|
||
<script>
|
||
function restartController() {
|
||
openDialog({title:'{{T "settings_system.vezerlo_ujrainditasa"}}', confirmLabel:'{{T "common.ujrainditas"}}',
|
||
message:'{{T "settings_system.biztosan_ujrainditja_a_vezerlot_a"}}',
|
||
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">{{T "settings_system.ujrainditas_folyamatban_ujracsatlakozas"}}</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:'{{T "settings_system.kiszolgalo_ujrainditasa"}}', confirmLabel:'{{T "common.ujrainditas"}}',
|
||
message:'{{T "settings_system.biztosan_ujrainditja_a_kiszolgalot_az"}}',
|
||
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">{{T "settings_system.ujrainditas_folyamatban_a_vezerlopult_ne"}}</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">{{T "settings_system.az_ujrainditas_a_vartnal_tovabb"}}</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}}
|