89712563a0
gates / gates (push) Successful in 10s
The retrieval clause rendered unconditionally on every page and is false on a reachable state - the same screen where the orphan card says we cannot tell. The condition is a fingerprint PINNED at the decision, not a comparison against the current key. The obvious proxy asks about the wrong key: the set-aside copies were written under an older key the box no longer has, so on a twice-rebuilt box the proxy promises about copies nothing can open. Demonstrated - under the proxy, the replaced-package and legacy cases both flip back to promising. The pin is a recorded assumption and says so: nothing on the box records which key wrote those copies. Empty is not a match. A countdown started before this carries no pin and takes the cautious branch, not a backfill. A sweep of all 36 templates found a fourth instance (backups page, same condition applied) and a fifth (the confirmation screen, correctly left alone - true at the moment of the decision). New retrieval_promise_gate registers each claim with a reason rather than banning a verb: a string ban failed twice, and the honest replacement copy contains the stem.
371 lines
28 KiB
HTML
371 lines
28 KiB
HTML
{{define "backups_remote"}}
|
||
{{template "layout_start" .}}
|
||
|
||
<div class="page-header">
|
||
<h2>Biztonsági mentés — Távoli mentés</h2>
|
||
<span class="domain-badge">{{.Domain}}</span>
|
||
</div>
|
||
|
||
{{template "backups_flash" .}}
|
||
|
||
{{if .RecoveryOffer}}
|
||
<!-- R-193: the PERMANENT entry point. Bound to RecoveryOffer, never to the postpone flag — a
|
||
customer who clicked "Most nem" once must not lose the route to their own data. -->
|
||
<div class="alert alert-warning">
|
||
<strong>A korábbi, házon kívüli mentéseid visszaszerezhetők.</strong>
|
||
Ezt a gépet újratelepítették, és a Felhom központi rendszere őriz hozzá egy lezárt csomagot. A
|
||
helyreállítási kódoddal feloldhatod a korábbi mentéseidet, és megnézheted, mi van bennük.
|
||
<div class="form-actions" style="margin-top:.5rem">
|
||
<a href="/recovery" class="btn btn-primary">Adatok visszaszerzése</a>
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
|
||
{{if not .Backup}}
|
||
{{template "backups_empty" .}}
|
||
{{else}}
|
||
|
||
<!-- Felhom-offsite status card (v0.124.0, decision 2): three honest states from LOCAL data only —
|
||
display + opt-in pointers, NEVER a state change (no form, no button in this card). State 3
|
||
(applied + apps toggled) is the existing status block below; the card renders nothing then. -->
|
||
{{if and (not .OffboxConfigured) .OffsiteHubEnabled}}
|
||
<!-- R-70 (v0.161.0): hub-managed offsite is provisioned for this box — "igényelhető" would be a
|
||
lie (it is already ordered) and the bare empty state hid the pre-apply window (DIAG-f10). -->
|
||
<div class="alert alert-info" style="margin-bottom:1rem" id="felhom-offsite-card">Felhom offsite tárhely kiépítve — a beállítás automatikus, folyamatban. Ha egy napon belül nem áll be, jelezd az üzemeltetőnek.</div>
|
||
{{else if not .OffboxConfigured}}
|
||
<div class="alert alert-info" style="margin-bottom:1rem" id="felhom-offsite-card">Felhom offsite tárhely — igényelhető szolgáltatás. Titkosított, házon kívüli másolat a mentéseidről. Érdeklődj az üzemeltetőnél.</div>
|
||
{{else if eq .OffboxToggledCount 0}}
|
||
<div class="alert alert-info" style="margin-bottom:1rem" id="felhom-offsite-card">Aktív — nincs kijelölt alkalmazás</div>
|
||
{{end}}
|
||
|
||
<!-- Off-box (NAS) backup — Part B: encrypted restic repo over SFTP (the off-site 3-2-1 leg). -->
|
||
<h3 id="offbox-section" class="backup-tier-divider">Távoli mentés (3. mentés) — titkosított, offsite</h3>
|
||
<p class="form-hint" style="margin:-0.25rem 0 1rem">Az alkalmazás-mentések titkosított másolata egy távoli tárolóra — saját NAS vagy Felhom offsite tárhely — restic + SFTP kapcsolaton. A tároló csak titkosított adatot lát. Ez a 3-2-1 szabály „1 off-site" lába — független a helyi másodpéldánytól és a teljes rendszermentéstől.</p>
|
||
<div class="card" style="margin-bottom:1.5rem">
|
||
{{if .Offbox}}
|
||
<div class="stats-grid backup-page-cards">
|
||
<div class="stat-card {{if or (eq .Offbox.LastStatus "error") (eq .Offbox.LastStatus "incomplete")}}stat-warn{{end}}">
|
||
<div class="stat-value" id="offbox-status-value" style="font-size:1.15rem">{{if eq .Offbox.LastStatus "ok"}}✓ Rendben{{else if eq .Offbox.LastStatus "incomplete"}}! Hiányos{{else if eq .Offbox.LastStatus "error"}}✗ Hiba{{else if eq .Offbox.LastStatus "running"}}Fut…{{else}}–{{end}}</div>
|
||
<div class="stat-label">Utolsó távoli mentés{{if .Offbox.LastRun}}<br><span class="relative-time">{{timeAgoStr .Offbox.LastRun}}</span>{{end}}</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value" style="font-size:1.15rem">{{if and .Offbox.StatsKnown .Offbox.RepoSizeHuman}}{{.Offbox.RepoSizeHuman}}{{else}}–{{end}}</div>
|
||
<div class="stat-label">Tároló méret · {{if .Offbox.StatsKnown}}{{.Offbox.SnapshotCount}} pillanatkép{{else}}a pillanatképek száma még ismeretlen{{end}}</div>
|
||
</div>
|
||
<div class="stat-card">
|
||
<div class="stat-value" style="font-size:1.05rem">{{if .Offbox.Enabled}}{{.Offbox.User}}@{{.Offbox.Host}}{{else}}Kikapcsolva{{end}}</div>
|
||
<div class="stat-label">{{if .Offbox.Enabled}}{{.Offbox.RepoPath}}{{else}}A távoli mentés ki van kapcsolva{{end}}</div>
|
||
</div>
|
||
</div>
|
||
{{if and .Offbox.Enabled (gt .Offbox.QuotaGB 0)}}
|
||
<!-- R-225: the BAR renders only when the fill is known. A 0%-wide bar over an unread store is a
|
||
picture of emptiness, and a picture is a claim. -->
|
||
<!-- SLICE 4: soft-quota usage bar (shared model; quota_gb from the hub descriptor). -->
|
||
<div id="offbox-quota-bar" style="max-width:560px;margin:.5rem 0">
|
||
<div class="stat-label" style="margin-bottom:.25rem">Tárhelykeret: {{if .Offbox.StatsKnown}}{{if .Offbox.RepoSizeHuman}}{{.Offbox.RepoSizeHuman}}{{else}}0{{end}} / {{.Offbox.QuotaGB}} GB ({{.OffboxQuotaPct}}%){{else}}még nem tudjuk, mennyi van a tárolóban — legfeljebb {{.Offbox.QuotaGB}} GB{{end}}</div>
|
||
{{if .Offbox.StatsKnown}}<div style="background:var(--border,#334);border-radius:4px;height:8px;overflow:hidden">
|
||
<div style="height:8px;border-radius:4px;width:{{.OffboxQuotaPct}}%;background:{{if ge .OffboxQuotaPct 100}}var(--crit,#e5484d){{else if ge .OffboxQuotaPct 80}}var(--warn,#f5a524){{else}}var(--ok,#30a46c){{end}}"></div>
|
||
</div>{{end}}
|
||
</div>
|
||
{{end}}
|
||
{{/* R-228 — THE SET-ASIDE HISTORY IS SAID OUT LOUD.
|
||
The customer chose "I do not want the old data", was told it would be KEPT and not deleted,
|
||
and then it vanished from every screen: the box recorded exactly where it went
|
||
(OrphanedRenamedTo) and showed that to nobody. Measured 2026-08-05 (CAMPAIGN-11 F7) —
|
||
12 535 KB at a path with zero references in any template or handler.
|
||
|
||
NOTE — IT STATES TWO FACTS AND STOPS. It does NOT promise the history can be reopened, because it
|
||
cannot be: serving a superseded package is an unbuilt link (R-199's inventory). A conditional
|
||
promise that turns out false is worse here than saying less — the R-202 lesson. */}}
|
||
{{if .Offbox.OrphanedRenamedTo}}
|
||
<div class="alert alert-info" style="margin-top:.75rem">
|
||
<p><strong>A korábbi mentéseid félre vannak téve — nem töröltük őket.</strong></p>
|
||
<p class="form-hint">Amikor új mentési kulcsot kapott a géped, a régebbi előzményt átmozgattuk
|
||
a távoli tárhelyen, és ott is maradt. <strong>Megnyitni innen egyelőre nem lehet</strong>, és
|
||
ez nem a kódodon múlik. Ha szükséged van rá, keresd a Felhom ügyfélszolgálatát.</p>
|
||
</div>
|
||
{{end}}
|
||
{{if .Offbox.LastError}}<p class="form-hint" style="color:var(--crit)">Utolsó hiba: {{.Offbox.LastError}}</p>{{end}}
|
||
{{/* Part E: display pick — a stale zero-toggle warning is replaced once the selection
|
||
changed (neutral color: the replacement is reassurance, not a deviation). */}}
|
||
{{if .OffboxWarningDisplay}}<p class="form-hint"{{if eq .OffboxWarningDisplay .Offbox.LastWarning}} style="color:var(--warn)"{{end}}>{{.OffboxWarningDisplay}}</p>{{end}}
|
||
{{/* v0.142.0 offsite-repo continuity: the ORPHANED card replaces the raw restic error banner. The
|
||
remote holds backups written under a previous, no-longer-available key (reinstall shape). A
|
||
reset moves the old history aside (never deletes) and starts a fresh repo under the current key. */}}
|
||
{{if eq .Offbox.RepoState "orphaned"}}
|
||
<div class="card" style="border-left:3px solid var(--crit,#e5484d);margin:.75rem 0;padding:.75rem 1rem" id="offbox-orphan-card">
|
||
<p style="margin:0 0 .35rem;font-weight:600">A távoli tároló másik kulccsal készült mentéseket tartalmaz</p>
|
||
{{/* R-299: this paragraph carried the SAME unevaluable promise as the confirm block below, in a
|
||
different conjugation („visszaállíthatók lehetnek" vs „visszaállítható lehet") — which is
|
||
also why the first regression guard, matching the singular form, did not catch it. The
|
||
discriminator is superseded identity_blob on the HUB; the box has no wire field for it. The
|
||
two accurate halves are kept: the store IS orphaned, and new backups genuinely cannot be
|
||
written. The guard now matches the STEM, so any inflection fails the test. */}}
|
||
<p class="form-hint" style="margin:0 0 .5rem">A távoli tárhelyen lévő mentések egy korábbi, már nem elérhető kulccsal készültek (jellemzően újratelepítés után). Emiatt új mentés jelenleg nem írható a tárolóba. A meglévő mentések nem sérültek. Azt viszont ez a gép nem tudja megállapítani, hogy később megnyithatók-e — ez attól függ, megvan-e még a hozzájuk tartozó kulcs. Ha szükséged van rájuk, írj nekünk.</p>
|
||
<button type="button" class="btn btn-sm btn-outline" id="orphan-reveal" onclick="var c=document.getElementById('orphan-confirm');c.style.display='block';this.style.display='none'">Új távoli mentés indítása…</button>
|
||
<div id="orphan-confirm" style="display:none;margin-top:.6rem">
|
||
{{/* R-294 / R-202: this paragraph promised the set-aside copies "may be restorable later
|
||
with the recovery code". The discriminator is host_escrow_superseded.identity_blob,
|
||
which lives on the HUB; the box caches only HubEscrowIdentityPresent (about the
|
||
CURRENT escrow) and no report or ACK field carries superseded-blob retention. So the
|
||
renderer cannot evaluate the condition it was stating — and a conditional promise the
|
||
system cannot evaluate is the same defect as an unconditional false one. It now
|
||
states what it knows, declines what it does not, and names a route.
|
||
Copy is verbatim from documentation/design/SPEC-orphan-card-copy-2026-08-10.md §4. */}}
|
||
<p class="form-hint" style="margin:0 0 .5rem">A régi előzmény <strong>félretéve marad a tárhelyen — nem töröljük</strong>. Új, üres tárolót hozunk létre, és a következő mentés oda készül.</p>
|
||
<p class="form-hint" style="margin:0 0 .5rem"><strong>A félretett mentések megnyithatóságát itt nem tudjuk megígérni.</strong> Ez attól függ, megvan-e még a hozzájuk tartozó kulcs, és ezt ez a gép nem tudja megállapítani. Ha szeretnéd, hogy utánanézzünk, <strong>írj nekünk</strong> — a félretett másolat addig is a helyén marad.</p>
|
||
<form method="POST" action="/backup/offbox/reset" style="display:inline">{{.CSRFField}}
|
||
<input type="hidden" name="confirm" value="1">
|
||
<button type="submit" class="btn btn-sm btn-primary">Megerősítés — új távoli mentés indítása</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
{{/* Escrow ceremony card (v0.127.0): the customer-driveable wizard replaced the manual-confirm
|
||
button (that deprecated endpoint stays for legacy blobs; its button is gone). States:
|
||
awaiting (v0.138.0: ceremony done, hub confirm pending) → info; awaiting timed out → warn +
|
||
re-ceremony CTA; pending → CTA; escrowed+stale → warning + re-ceremony CTA; escrowed clean →
|
||
secondary link; agent too old → the honest version note, no CTA. */}}
|
||
{{if .OffboxCeremonyAwaiting}}
|
||
{{/* v0.138.0: the report-cycle gap between a completed ceremony and the hub-verified flip.
|
||
Info (blue) accent — NOT a warning: nothing is wrong, the confirmation is simply in flight. */}}
|
||
<div class="card" style="border-left:3px solid var(--blue);margin:.75rem 0;padding:.75rem 1rem">
|
||
<p style="margin:0 0 .35rem"><strong>Helyreállítási kód létrehozva</strong></p>
|
||
<p class="form-hint" style="margin:0">A helyreállítási csomag elküldve a központba, megerősítésre vár — ez általában néhány másodperc, legfeljebb 15 perc.</p>
|
||
</div>
|
||
{{else if .OffboxCeremonyTimedOut}}
|
||
{{/* v0.138.0: the confirmation never arrived within two report cycles + slack — degrade to a
|
||
warning with the re-ceremony CTA, never an indefinite "waiting". */}}
|
||
<div class="card" style="border-left:3px solid var(--warn);margin:.75rem 0;padding:.75rem 1rem">
|
||
<p class="form-hint" style="color:var(--warn);margin:0 0 .5rem">A megerősítés nem érkezett meg a várt időn belül. Ellenőrizze az internetkapcsolatot, majd készítsen új helyreállítási kódot.</p>
|
||
{{if .EscrowAgentOK}}
|
||
<a href="/backup/escrow" class="btn btn-sm btn-primary">Új helyreállítási kód készítése</a>
|
||
{{else}}
|
||
<p class="form-hint" style="margin:0">A funkcióhoz az ügynök frissítése szükséges — a frissítés automatikusan megérkezik.</p>
|
||
{{end}}
|
||
</div>
|
||
{{else if and .OffboxConfigured (ne .Offbox.EscrowState "escrowed")}}
|
||
<div class="card" style="border-left:3px solid var(--warn);margin:.75rem 0;padding:.75rem 1rem">
|
||
<p style="margin:0 0 .35rem"><strong>Helyreállítási kód szükséges</strong></p>
|
||
<p class="form-hint" style="margin:0 0 .5rem">A távoli mentések csak akkor állíthatók vissza egy teljes meghibásodás után, ha létrehozza a helyreállítási kódot.</p>
|
||
{{/* §7.3 / Q7 — THE TRAP THAT MUST NOT SURVIVE THIS SESSION. While a recovery is outstanding,
|
||
creating a NEW code seals the CURRENT key and demotes the package that opens the earlier
|
||
history to retained custody, which no shipped path can read (R-199). It also re-enables
|
||
the recovery screen through the orphan route while invalidating the code that screen
|
||
accepts. The button is therefore made UNAVAILABLE here rather than merely captioned:
|
||
a warning beside a button is a warning people click past. */}}
|
||
{{if .RecoveryOffer}}
|
||
<p class="form-hint" style="margin:0">
|
||
Ehhez a géphez <strong>egy korábbi helyreállítási kód tartozik</strong>, és a korábbi mentéseid még megvannak.
|
||
Új kód létrehozása <strong>a régi mentéseidet elérhetetlenné tenné</strong>, ezért most nem indítható.
|
||
Előbb <a href="/recovery">add meg a meglévő kódodat</a> — vagy ott jelezheted, ha nem kéred vissza a korábbi adatokat.
|
||
</p>
|
||
{{else if .EscrowAgentOK}}
|
||
<a href="/backup/escrow" class="btn btn-sm btn-primary">Helyreállítási kód létrehozása</a>
|
||
{{else}}
|
||
<p class="form-hint" style="margin:0">A funkcióhoz az ügynök frissítése szükséges — a frissítés automatikusan megérkezik.</p>
|
||
{{end}}
|
||
</div>
|
||
{{else if and .OffboxConfigured .EscrowStale}}
|
||
<div class="card" style="border-left:3px solid var(--warn);margin:.75rem 0;padding:.75rem 1rem">
|
||
<p class="form-hint" style="color:var(--warn);margin:0 0 .5rem">A letétben lévő helyreállítási csomag nem fedi a jelenlegi távoli mentési jelszót. Hozzon létre új helyreállítási kódot.</p>
|
||
{{if .EscrowAgentOK}}
|
||
<a href="/backup/escrow" class="btn btn-sm btn-primary">Új helyreállítási kód készítése</a>
|
||
{{else}}
|
||
<p class="form-hint" style="margin:0">A funkcióhoz az ügynök frissítése szükséges — a frissítés automatikusan megérkezik.</p>
|
||
{{end}}
|
||
</div>
|
||
{{else if .OffboxConfigured}}
|
||
{{/* v0.127.1: the re-ceremony CTA is a real secondary button (outline, NOT primary — escrowed
|
||
is a healthy state; available-not-urgent, unlike the stale variant above). */}}
|
||
<div style="margin:.5rem 0">
|
||
<p class="form-hint" style="margin:0 0 .4rem">A helyreállítási kód letétbe helyezve.</p>
|
||
{{if .EscrowAgentOK}}<a href="/backup/escrow" class="btn btn-sm btn-outline">Új helyreállítási kód készítése</a>{{end}}
|
||
</div>
|
||
{{end}}
|
||
{{if .AbandonActive}}
|
||
{{/* R-241: the countdown, stated for the whole window on the page the choice was made from. */}}
|
||
<div class="card" style="border-left:3px solid var(--warn);margin:.75rem 0;padding:.75rem 1rem">
|
||
<p style="margin:0 0 .35rem"><strong>A korábbi mentések törlése folyamatban</strong></p>
|
||
<p class="form-hint" style="margin:0 0 .5rem">
|
||
{{/* R-302: the FOURTH instance of the retrieval promise, under a different verb than the
|
||
banner's — which is why no earlier guard counted it. Same condition, same single
|
||
derivation: fixing the strip above and not this would leave one page contradicting the
|
||
other. The deletion and its date are certain and always render. */}}
|
||
A kérésed szerint a korábbi távoli mentéseidet <strong>{{.AbandonDate}}</strong> napján véglegesen töröljük
|
||
(még <strong>{{.AbandonDaysLeft}} nap</strong>).
|
||
{{if .AbandonRetrievalOffered}}Addig meggondolhatod magad: ha megvan a helyreállítási kódod,
|
||
a mentéseid visszaszerezhetők, és a törlés elmarad.{{else}}Hogy ezek még visszaszerezhetők-e a helyreállítási kóddal, azt innen nem tudjuk megállapítani — ha vissza szeretnéd kapni őket, <strong>írj nekünk a törlés előtt</strong>.{{end}}
|
||
</p>
|
||
<a href="/recovery" class="btn btn-sm btn-primary">Mégis visszaszerzem a kóddal</a>
|
||
</div>
|
||
{{else if .AbandonPurging}}
|
||
<div class="card" style="border-left:3px solid var(--border,#2a3142);margin:.75rem 0;padding:.75rem 1rem">
|
||
<p class="form-hint" style="margin:0">A korábbi távoli mentéseid törlése megtörtént. A hozzájuk tartozó lezárt helyreállítási csomag eltávolítása még folyamatban van.</p>
|
||
</div>
|
||
{{end}}
|
||
{{if .OffboxConfigured}}
|
||
<div class="schedule-actions" style="margin-top:1rem">
|
||
<form method="POST" action="/backup/offbox/run" style="display:inline">{{.CSRFField}}
|
||
<button type="submit" class="btn btn-sm btn-primary">Távoli mentés most</button>
|
||
</form>
|
||
</div>
|
||
<!-- v0.147.0 (4c): live progress for a MANUAL run — total bytes, percent and which app is being
|
||
pushed, parsed from restic's --json status stream. Hidden until a run reports progress; the
|
||
nightly run never populates it. -->
|
||
<div id="offbox-progress" class="alert alert-info" style="display:none;margin-top:.75rem">
|
||
<span id="offbox-progress-text"></span>
|
||
<div class="progress-bar-task" style="margin-top:.5rem">
|
||
<div id="offbox-progress-bar" class="progress-fill" style="width:0%"></div>
|
||
</div>
|
||
</div>
|
||
<h4 style="margin-top:1.25rem">Mely alkalmazások mentődnek a távoli tárolóra?</h4>
|
||
{{if and .OffboxApps (eq .Offbox.EscrowState "escrowed") (eq .OffboxToggledCount 0)}}
|
||
<p class="form-hint">Nincs távoli mentésre jelölt alkalmazás — jelölj ki legalább egyet.</p>
|
||
{{end}}
|
||
{{if .OffboxApps}}
|
||
<div class="app-row-list">
|
||
{{range .OffboxApps}}
|
||
{{template "app_list_row" dict "Slug" .Slug "Name" .DisplayName}}
|
||
<form method="POST" action="/backup/offbox/toggle" style="display:inline">{{$.CSRFField}}
|
||
<input type="hidden" name="app" value="{{.Name}}">
|
||
<input type="hidden" name="enabled" value="{{if .Enabled}}false{{else}}true{{end}}">
|
||
<button type="submit" class="btn btn-xs {{if .Enabled}}btn-outline{{else}}btn-primary{{end}}">{{if .Enabled}}Távoli mentés kikapcsolása{{else}}Távoli mentés bekapcsolása{{end}}</button>
|
||
</form>
|
||
{{if $.OffboxBlockedSet}}{{if index $.OffboxBlockedSet .Name}}
|
||
<span class="form-hint" style="display:block;margin-top:.25rem">A teljes mentés túllépné a tárhelykeretet — csak a konfiguráció és az adatbázis kerül mentésre.</span>
|
||
{{end}}{{end}}
|
||
{{template "app_list_row_end"}}
|
||
{{end}}
|
||
</div>
|
||
{{else}}<p class="form-hint">Nincs telepített alkalmazás.</p>{{end}}
|
||
{{end}}
|
||
{{else}}
|
||
{{if .OffsiteHubEnabled}}
|
||
<p class="form-hint">Felhom offsite tárhely kiépítve — a beállítás automatikus, folyamatban. Ha egy napon belül nem áll be, jelezd az üzemeltetőnek.</p>
|
||
{{else}}
|
||
<p class="form-hint">Még nincs beállítva távoli mentési cél.</p>
|
||
{{end}}
|
||
{{end}}
|
||
|
||
<details style="margin-top:1rem">
|
||
<summary class="btn btn-xs btn-primary" style="cursor:pointer;display:inline-block">Távoli mentési cél beállítása</summary>
|
||
<form method="POST" action="/backup/offbox/config" style="margin-top:.75rem;padding:1rem;border:1px solid var(--border,#ddd);border-radius:6px;max-width:560px">{{.CSRFField}}
|
||
<div class="form-row"><label>Cél címe (IP vagy hosztnév — NAS vagy SFTP-kiszolgáló)</label><input type="text" name="host" class="form-input" value="{{if .Offbox}}{{.Offbox.Host}}{{end}}" placeholder="pl. 192.168.0.10"></div>
|
||
<div class="form-row"><label>SSH port</label><input type="number" name="port" class="form-input" value="{{if .Offbox}}{{.Offbox.Port}}{{else}}22{{end}}"></div>
|
||
<div class="form-row"><label>Felhasználó</label><input type="text" name="user" class="form-input" value="{{if .Offbox}}{{.Offbox.User}}{{end}}" placeholder="pl. felhom"></div>
|
||
<div class="form-row"><label>Tároló útvonala a célgépen</label><input type="text" name="repo_path" class="form-input" value="{{if .Offbox}}{{.Offbox.RepoPath}}{{end}}" placeholder="pl. /volume1/felhom-backup/repo"></div>
|
||
<div class="form-row"><label><input type="checkbox" name="enabled" {{if .Offbox}}{{if .Offbox.Enabled}}checked{{end}}{{else}}checked{{end}}> Napi automatikus távoli mentés engedélyezve</label></div>
|
||
<div class="form-row"><label>SSH privát kulcs {{if .OffboxConfigured}}(üresen hagyva változatlan){{end}}</label>
|
||
<textarea name="ssh_key" class="form-input" rows="4" autocomplete="off" placeholder="-----BEGIN OPENSSH PRIVATE KEY-----"></textarea>
|
||
<span class="form-hint">A kulcsot 0600-as fájlba írjuk; sosem naplózzuk és nem tároljuk a beállításokban.</span></div>
|
||
<div class="form-row"><label>A célgép ismert-host sora (known_hosts) {{if .OffboxConfigured}}(üresen hagyva változatlan){{end}}</label>
|
||
<textarea name="known_hosts" class="form-input" rows="2" autocomplete="off" placeholder="nas.local ssh-ed25519 AAAA…"></textarea>
|
||
<span class="form-hint">A host-kulcs rögzítése (no blind TOFU). Lekérdezhető: <span class="mono">ssh-keyscan -p <port> <host></span></span></div>
|
||
<button type="submit" class="btn btn-sm btn-primary" style="margin-top:.5rem">Mentés</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
{{end}}
|
||
|
||
<script>
|
||
/* Part C (v0.142.0) + 4c (v0.147.0): poll the run status, render live progress for a manual run, and
|
||
reload once it reaches a terminal state so the customer sees Rendben/Hiba + fresh numbers WITHOUT a
|
||
manual reload.
|
||
|
||
v0.147.0 changed WHEN polling starts. It used to begin only if the page already rendered "Fut…",
|
||
which loses a race the manual trigger always runs: the POST redirects and this page renders before
|
||
the detached goroutine has written LastStatus=running, so the poll never armed and the customer
|
||
watched a static page during the very run they had just started. Now it always arms and gives up
|
||
after GRACE quiet ticks if nothing is (or ever was) in flight. */
|
||
(function(){
|
||
var v = document.getElementById('offbox-status-value');
|
||
var box = document.getElementById('offbox-progress');
|
||
var text = document.getElementById('offbox-progress-text');
|
||
var bar = document.getElementById('offbox-progress-bar');
|
||
var GRACE = 5; // ~15s of quiet before concluding nothing is running
|
||
var quiet = 0;
|
||
var sawRunning = (v && v.textContent.indexOf('Fut') >= 0);
|
||
|
||
var timer = setInterval(function(){
|
||
fetch('/backup/offbox/status',{headers:{'Accept':'application/json'}})
|
||
.then(function(r){return r.json();})
|
||
.then(function(d){
|
||
if(!d) return;
|
||
var p = d.progress || {};
|
||
var running = (d.status === 'running') || p.active;
|
||
|
||
if(running){
|
||
sawRunning = true; quiet = 0;
|
||
if(p.active && box){
|
||
/* Only claim a percentage once restic has told us a total — before the scan finishes,
|
||
percent is 0 of 0, and a bar pinned at 0% reads as "stuck" rather than "measuring". */
|
||
/* A run is not only the per-app loop: the shares leg and the retention/prune step follow
|
||
it and can dominate the wall clock (40 of 57 seconds, measured). Name them, or the
|
||
card freezes on the last app's finished counters for that whole tail. */
|
||
/* The dump pre-phase runs BEFORE the per-app loop (R-44): it refreshes every app's
|
||
database dump so the snapshot pairs this run's files with this run's DB. On an app
|
||
with a large database it can dominate the early wall clock, and an unnamed silent
|
||
stretch at the start reads as a hang. */
|
||
if(p.phase === 'dump'){
|
||
text.textContent = 'Adatbázisok mentése a pillanatképhez…';
|
||
bar.style.width = '100%';
|
||
box.className = 'alert alert-info'; box.style.display = '';
|
||
return;
|
||
}
|
||
if(p.phase === 'retention'){
|
||
text.textContent = 'Karbantartás: régi mentések rendezése a távoli tárolón…';
|
||
bar.style.width = '100%';
|
||
box.className = 'alert alert-info'; box.style.display = '';
|
||
return;
|
||
}
|
||
if(p.phase === 'shares'){
|
||
text.textContent = 'Megosztott mappák mentése…';
|
||
bar.style.width = '100%';
|
||
box.className = 'alert alert-info'; box.style.display = '';
|
||
return;
|
||
}
|
||
var label = p.current_app ? ('Mentés: ' + p.current_app) : 'Mentés folyamatban';
|
||
if(p.bytes_done > 0){
|
||
/* Bytes are genuinely moving — the informative case. */
|
||
label += ' — ' + Math.round(p.percent) + '% (' + p.done_human + ' / ' + p.total_human + ')';
|
||
bar.style.width = Math.max(0, Math.min(100, p.percent)) + '%';
|
||
} else if(p.total_files > 0){
|
||
/* No bytes moving. restic 0.14 only counts a file into bytes_done/files_done when it
|
||
COMPLETES, so an app dominated by one big archive freezes both counters — measured
|
||
on the demo box: immich at 1 of 46 files, 0 bytes, for 42 seconds while restic
|
||
worked through a single ~430MB volume tar. A percentage cannot move in that window,
|
||
so do not pretend: name the file being processed and the elapsed time, which is
|
||
what actually tells the customer it is alive. */
|
||
var fpct = Math.round((p.files_done / p.total_files) * 100);
|
||
label += ' — ' + p.files_done + ' / ' + p.total_files + ' fájl'
|
||
+ (p.total_human ? ' (' + p.total_human + ')' : '');
|
||
if(p.current_file){
|
||
var base = p.current_file.split('/').pop();
|
||
label += ' · feldolgozás alatt: ' + base;
|
||
}
|
||
if(p.elapsed_sec > 0){ label += ' · ' + p.elapsed_sec + ' mp'; }
|
||
bar.style.width = Math.max(0, Math.min(100, fpct)) + '%';
|
||
} else {
|
||
label += ' — a mentendő adatok felmérése…';
|
||
bar.style.width = '0%';
|
||
}
|
||
text.textContent = label;
|
||
box.style.display = '';
|
||
}
|
||
return;
|
||
}
|
||
|
||
/* Not running. Terminal only if we ever saw it running — otherwise this is the pre-start
|
||
race (or a page nobody triggered anything from). */
|
||
if(sawRunning){ clearInterval(timer); location.reload(); return; }
|
||
if(++quiet >= GRACE){ clearInterval(timer); }
|
||
})
|
||
.catch(function(){ /* transient — keep polling */ });
|
||
}, 3000);
|
||
})();
|
||
</script>
|
||
|
||
{{template "layout_end" .}}
|
||
{{end}}
|