i18n slice 1 release C: storage, sharing, sign-in, guest, catch-all and debug pages in English
- 11 templates converted (storage, storage_network, storage_init, storage_attach, sharing, login,
claim, launcher_shared, launcher_share_password, catchall, debug); every key translated.
Six ASCII-only Hungarian JS fragments the extractor missed were found by eye and converted by hand
(", majd a(z)", "FIGYELEM:", "jelenlegi:", "mp", "p", " db").
- login, claim, both guest share pages and the catch-all render through executeTemplateLang (the
household language; no session CSRF, no escrow reminder). renderLogin now takes the request.
- Page titles: TitleKey for storage, network storage, the two drive wizards and sharing.
TestHandlerTitleKeysMatchHungarianTitle pins handler literal == hu.json value for every TitleKey.
- Tests: TestDirectRenderHandlersFollowLanguage (real routes, en + hu),
TestI18nDirectRenderPagesHaveNoAdminChrome (escrow reminder due; none on the guest page).
- Fixture correction: the release C cases had invented page titles; the cases now carry the handlers'
real titles (and the wizard pages their real page name), and those 12 fixtures were RE-CAPTURED from
the unconverted templates at 0555091. The diff to the old fixtures is the <title> line (and the nav
highlight on the two wizard pages) only.
- i18n gate: HU_FORMAL_CEILING 12 -> 16 — four more „ön" forms in the converted copy, unchanged by rule (R-516).
Hungarian: byte-identical (TestI18nParity against fixtures from unconverted templates).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -2,13 +2,13 @@
|
||||
{{template "layout_start" .}}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Tárhely — Meghajtók</h2>
|
||||
<h2>{{T "storage.tarhely_meghajtok"}}</h2>
|
||||
</div>
|
||||
|
||||
<!-- Section: Storage Paths -->
|
||||
<div class="settings-card">
|
||||
<h3>Adattárolók</h3>
|
||||
<p class="settings-card-desc">Külső meghajtók kezelése alkalmazásadatok tárolásához.</p>
|
||||
<h3>{{T "storage.adattarolok"}}</h3>
|
||||
<p class="settings-card-desc">{{T "storage.kulso_meghajtok_kezelese_alkalmazasadato"}}</p>
|
||||
|
||||
{{if .StorageError}}<div class="alert alert-error">{{.StorageError}}</div>{{end}}
|
||||
{{if .StorageSuccess}}<div class="alert alert-info">{{.StorageSuccess}}</div>{{end}}
|
||||
@@ -21,49 +21,49 @@
|
||||
<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"><svg class="ico ico-sm"><use href="#i-pencil"/></svg></button>{{end}}
|
||||
{{if not (or .Disconnected .Decommissioned)}}<button class="btn btn-xs btn-ghost" onclick="editStorageLabel('{{.Path}}', '{{.Label}}')" title="{{T "storage.atnevezes"}}"><svg class="ico ico-sm"><use href="#i-pencil"/></svg></button>{{end}}
|
||||
</div>
|
||||
<span class="storage-path-path mono">{{.Path}}</span>
|
||||
</div>
|
||||
<div class="storage-path-badges">
|
||||
{{if .Disconnected}}
|
||||
<span class="badge badge-error">Leválasztva</span>
|
||||
<span class="badge badge-error">{{T "storage.levalasztva"}}</span>
|
||||
{{else if .Decommissioned}}
|
||||
<span class="tag tag-off"><span class="dot"></span>Kiváltva</span>
|
||||
<span class="tag tag-off"><span class="dot"></span>{{T "storage.kivaltva"}}</span>
|
||||
{{else}}
|
||||
{{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 .IsDefault}}<span class="tag">{{T "storage.alapertelmezett"}}</span>{{end}}
|
||||
{{if .Schedulable}}<span class="tag tag-run"><span class="dot"></span>{{T "storage.aktiv"}}</span>{{else}}<span class="tag tag-off"><span class="dot"></span>{{T "storage.inaktiv"}}</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}}
|
||||
{{if not .IsMounted}}<span class="badge badge-warn">{{T "storage.rendszermeghajton"}}</span>{{end}}
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{if .Disconnected}}
|
||||
<div class="storage-path-details">
|
||||
<div class="storage-disconnected-info">
|
||||
{{if .DisconnectedAt}}<span class="form-hint">Leválasztva: {{.DisconnectedAt}}</span>{{end}}
|
||||
{{if .DisconnectedAt}}<span class="form-hint">{{T "storage.levalasztva_2"}}</span>{{end}}
|
||||
{{if .StoppedApps}}
|
||||
<span class="form-hint">Leállított alkalmazások: {{range $i, $name := .StoppedApps}}{{if $i}}, {{end}}{{$name}}{{end}}</span>
|
||||
<span class="form-hint">{{T "storage.leallitott_alkalmazasok"}} {{range $i, $name := .StoppedApps}}{{if $i}}, {{end}}{{$name}}{{end}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="storage-path-actions" id="storage-actions-{{.Path}}">
|
||||
<button class="btn btn-xs btn-primary" onclick="storageReconnect('{{.Path}}')">Csatlakoztatás</button>
|
||||
<button class="btn btn-xs btn-primary" onclick="storageReconnect('{{.Path}}')">{{T "storage.csatlakoztatas"}}</button>
|
||||
</div>
|
||||
{{else if .Decommissioned}}
|
||||
<div class="storage-path-details">
|
||||
<div class="storage-disconnected-info">
|
||||
<span class="form-hint">Adatok átköltöztetve ide: <strong>{{.MigratedToLabel}}</strong> ({{.MigratedTo}})</span>
|
||||
{{if .DecommissionedAt}}<span class="form-hint">Időpont: {{.DecommissionedAt}}</span>{{end}}
|
||||
<span class="form-hint">{{T "storage.adatok_atkoltoztetve_ide"}}</span>
|
||||
{{if .DecommissionedAt}}<span class="form-hint">{{T "storage.idopont"}}</span>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="storage-path-actions">
|
||||
<button class="btn btn-xs btn-primary" onclick="storageReEnroll('{{.Path}}','{{.Label}}')">Visszacsatlakoztatás</button>
|
||||
<button class="btn btn-xs btn-primary" onclick="storageReEnroll('{{.Path}}','{{.Label}}')">{{T "storage.visszacsatlakoztatas"}}</button>
|
||||
<form method="POST" action="/settings/storage/remove" style="display:inline"
|
||||
onsubmit="return storageRemoveDialog(event, this, 'Biztosan eltávolítja a(z) {{.Label}} ({{.Path}}) meghajtót a rendszerből?\n\nA meghajtó adatai NEM törlődnek.')">
|
||||
onsubmit="return storageRemoveDialog(event, this, '{{T "storage.biztosan_eltavolitja_meghajtot"}}')">
|
||||
{{$.CSRFField}}
|
||||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||||
<button type="submit" class="btn btn-xs btn-outline">Eltávolítás a rendszerből</button>
|
||||
<button type="submit" class="btn btn-xs btn-outline">{{T "storage.eltavolitas_a_rendszerbol"}}</button>
|
||||
</form>
|
||||
</div>
|
||||
{{else}}
|
||||
@@ -87,28 +87,28 @@
|
||||
{{end}}
|
||||
{{if .StoppedApps}}
|
||||
<div class="storage-stopped-apps-info" id="storage-stopped-{{.Path}}">
|
||||
<span class="form-hint" style="color:var(--blue-bright)">Újraindításra váró alkalmazások: {{range $i, $name := .StoppedApps}}{{if $i}}, {{end}}{{$name}}{{end}}</span>
|
||||
<button class="btn btn-xs btn-primary" onclick="storageRestartApps('{{.Path}}')" style="margin-left:.5rem">Alkalmazások indítása</button>
|
||||
<span class="form-hint" style="color:var(--blue-bright)">{{T "storage.ujrainditasra_varo_alkalmazasok"}} {{range $i, $name := .StoppedApps}}{{if $i}}, {{end}}{{$name}}{{end}}</span>
|
||||
<button class="btn btn-xs btn-primary" onclick="storageRestartApps('{{.Path}}')" style="margin-left:.5rem">{{T "storage.alkalmazasok_inditasa"}}</button>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="storage-path-meta">
|
||||
{{if .AppDetails}}
|
||||
<details class="storage-app-details">
|
||||
<summary class="form-hint" style="cursor:pointer">
|
||||
{{.AppCount}} alkalmazás használja
|
||||
{{T "storage.alkalmazas_hasznalja"}}
|
||||
</summary>
|
||||
<div class="storage-app-list">
|
||||
{{range .AppDetails}}
|
||||
<div class="storage-app-row">
|
||||
<a href="/apps/{{.Stack}}" class="storage-app-link">{{.Name}}</a>
|
||||
{{if .SizeHuman}}<span class="mono form-hint">{{.SizeHuman}}</span>{{end}}
|
||||
<span class="btn btn-xs btn-outline" style="opacity:.45;cursor:not-allowed" title="Hamarosan"><svg class="ico ico-sm"><use href="#i-upload"/></svg> Mozgatás</span>
|
||||
<span class="btn btn-xs btn-outline" style="opacity:.45;cursor:not-allowed" title="{{T "storage.hamarosan"}}"><svg class="ico ico-sm"><use href="#i-upload"/></svg> {{T "storage.mozgatas"}}</span>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</details>
|
||||
{{else}}
|
||||
<span class="form-hint">Nincs alkalmazás ezen a tárolón</span>
|
||||
<span class="form-hint">{{T "storage.nincs_alkalmazas_ezen_a_tarolon"}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="drive-agent-extra" id="agent-extra-{{.Path}}"></div>
|
||||
@@ -118,7 +118,7 @@
|
||||
<form method="POST" action="/settings/storage/default" style="display:inline">
|
||||
{{$.CSRFField}}
|
||||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||||
<button type="submit" class="btn btn-xs btn-outline">Legyen alapértelmezett</button>
|
||||
<button type="submit" class="btn btn-xs btn-outline">{{T "storage.legyen_alapertelmezett"}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
{{if .Schedulable}}
|
||||
@@ -126,18 +126,18 @@
|
||||
{{$.CSRFField}}
|
||||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||||
<input type="hidden" name="schedulable" value="false">
|
||||
<button type="submit" class="btn btn-xs btn-outline" title="A meghajtó kimarad az új alkalmazás-telepítésekből. A rajta lévő alkalmazások változatlanul futnak.">Új telepítések letiltása</button>
|
||||
<button type="submit" class="btn btn-xs btn-outline" title="{{T "storage.a_meghajto_kimarad_az_uj"}}">{{T "storage.uj_telepitesek_letiltasa"}}</button>
|
||||
</form>
|
||||
{{else}}
|
||||
<form method="POST" action="/settings/storage/schedulable" style="display:inline">
|
||||
{{$.CSRFField}}
|
||||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||||
<input type="hidden" name="schedulable" value="true">
|
||||
<button type="submit" class="btn btn-xs btn-outline" title="A meghajtó újra választható az új alkalmazás-telepítéseknél.">Új telepítések engedélyezése</button>
|
||||
<button type="submit" class="btn btn-xs btn-outline" title="{{T "storage.a_meghajto_ujra_valaszthato_az"}}">{{T "storage.uj_telepitesek_engedelyezese"}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
{{if .IsUSB}}
|
||||
<button class="btn btn-xs btn-danger-outline" onclick="storageDisconnect('{{.Path}}', '{{.Label}}', {{.AppCount}})" title="Az itt tárolt alkalmazások leállnak, a meghajtó biztonságosan kihúzható. Az adatok megmaradnak; a meghajtó később újra csatlakoztatható.">Biztonságos leválasztás</button>
|
||||
<button class="btn btn-xs btn-danger-outline" onclick="storageDisconnect('{{.Path}}', '{{.Label}}', {{.AppCount}})" title="{{T "storage.az_itt_tarolt_alkalmazasok_leallnak"}}">{{T "storage.biztonsagos_levalasztas"}}</button>
|
||||
{{end}}
|
||||
{{/* List-removal is the undo of a MANUAL add only. Wizard-enrolled drives
|
||||
(/mnt/felhom-drives/) have a real lifecycle — Biztonságos leválasztás /
|
||||
@@ -145,23 +145,23 @@
|
||||
what the customer wants, so the button is hidden for them. */}}
|
||||
{{if and (not .IsDefault) (eq .AppCount 0) (not .IsEnrolled)}}
|
||||
<form method="POST" action="/settings/storage/remove" style="display:inline"
|
||||
onsubmit="return storageRemoveDialog(event, this, 'Biztosan eltávolítja a(z) {{.Path}} adattárolót?')">
|
||||
onsubmit="return storageRemoveDialog(event, this, '{{T "storage.biztosan_eltavolitja_adattarolot"}}')">
|
||||
{{$.CSRFField}}
|
||||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||||
<button type="submit" class="btn btn-xs btn-danger-outline" title="Csak a nyilvántartásból törli a meghajtót — az adatok és a fájlrendszer érintetlenül maradnak.">Eltávolítás a listából</button>
|
||||
<button type="submit" class="btn btn-xs btn-danger-outline" title="{{T "storage.csak_a_nyilvantartasbol_torli_a"}}">{{T "storage.eltavolitas_a_listabol"}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
{{if and (gt .AppCount 0) .HasOtherPaths}}
|
||||
{{$src := .Path}}
|
||||
<span class="migrate-inline" style="display:inline-flex;gap:.35rem;align-items:center">
|
||||
<select id="migrate-target-{{.Path}}" class="btn btn-xs btn-outline">
|
||||
<option value="">Áthelyezés ide…</option>
|
||||
<option value="">{{T "storage.athelyezes_ide"}}</option>
|
||||
{{range $.StoragePaths}}{{if and (ne .Path $src) .Schedulable (not .Disconnected) (not .Decommissioned)}}<option value="{{.Path}}">{{.Label}} ({{.Path}})</option>{{end}}{{end}}
|
||||
</select>
|
||||
<button class="btn btn-xs btn-outline" onclick="storageMigrateAll('{{.Path}}','{{.Label}}')">Összes adat áthelyezése</button>
|
||||
<button class="btn btn-xs btn-outline" onclick="storageMigrateAll('{{.Path}}','{{.Label}}')">{{T "storage.osszes_adat_athelyezese"}}</button>
|
||||
</span>
|
||||
{{end}}
|
||||
<button class="btn btn-xs btn-danger-outline" onclick="storageDecommission('{{.Path}}','{{.Label}}',{{.AppCount}})" title="A meghajtó végleges kivonása a rendszerből. Ha céltárolót választ, előbb minden adat átkerül oda; áthelyezés nélkül az adatok a meghajtón maradnak.">Végleges leszerelés</button>
|
||||
<button class="btn btn-xs btn-danger-outline" onclick="storageDecommission('{{.Path}}','{{.Label}}',{{.AppCount}})" title="{{T "storage.a_meghajto_vegleges_kivonasa_a"}}">{{T "storage.vegleges_leszereles"}}</button>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
@@ -169,20 +169,20 @@
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="empty-state" style="padding:1.5rem">
|
||||
Nincs regisztrált adattároló. Adjon hozzá egyet az alábbi űrlappal.
|
||||
{{T "storage.nincs_regisztralt_adattarolo_adjon_hozza"}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
|
||||
<div id="migrate-progress" style="display:none;margin-top:1rem;padding:1rem;border:1px solid var(--blue);border-radius:6px;background:rgba(0,136,204,0.06)">
|
||||
<strong>Adatok áthelyezése</strong>
|
||||
<strong>{{T "storage.adatok_athelyezese"}}</strong>
|
||||
<div id="migrate-progress-body" style="margin-top:.5rem">…</div>
|
||||
</div>
|
||||
<script>
|
||||
// Shared migration progress (used by both migrate-all here and per-app migrate on the app page).
|
||||
function migFmtGB(b){ return (Number(b||0)/1e9).toFixed(1)+' GB'; }
|
||||
function migRender(job){
|
||||
var names={stop:'Alkalmazások leállítása',copy:'Adatok másolása',verify:'Ellenőrzés',flip:'Újratelepítés',redeploy:'Újratelepítés',cleanup:'Forrás törlése'};
|
||||
var names={stop:'{{T "storage.alkalmazasok_leallitasa"}}',copy:'{{T "storage.adatok_masolasa"}}',verify:'{{T "storage.ellenorzes"}}',flip:'{{T "storage.ujratelepites"}}',redeploy:'{{T "storage.ujratelepites"}}',cleanup:'{{T "storage.forras_torlese"}}'};
|
||||
var s=names[job.phase]||job.phase;
|
||||
if(job.current_app) s+=': '+job.current_app;
|
||||
if(job.phase==='copy'&&job.bytes_total>0){ s+=' ('+Math.floor(100*job.bytes_done/job.bytes_total)+'% — '+migFmtGB(job.bytes_done)+'/'+migFmtGB(job.bytes_total)+')'; }
|
||||
@@ -195,10 +195,10 @@
|
||||
function tick(){
|
||||
fetch('/api/storage/migrate/status').then(function(r){return r.json();}).then(function(d){
|
||||
var job=d.data&&d.data.job;
|
||||
if(!job){ if(body) body.textContent='Nincs folyamatban migráció.'; return; }
|
||||
if(!job){ if(body) body.textContent='{{T "storage.nincs_folyamatban_migracio"}}'; 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==='aborted'){ if(body) body.innerHTML+='<br><strong style="color:var(--danger,#c0392b)">Megszakadt: '+(job.error||'')+'</strong><br>A forrás adatai érintetlenek.'; return; }
|
||||
if(job.phase==='done'){ if(body) body.innerHTML+='<br><strong>{{T "storage.kesz"}}</strong>'; setTimeout(function(){location.reload();},1500); return; }
|
||||
if(job.phase==='aborted'){ if(body) body.innerHTML+='<br><strong style="color:var(--danger,#c0392b)">{{T "storage.megszakadt"}} '+(job.error||'')+'</strong><br>{{T "storage.a_forras_adatai_erintetlenek"}}'; return; }
|
||||
setTimeout(tick,1500);
|
||||
}).catch(function(){ setTimeout(tick,2000); });
|
||||
}
|
||||
@@ -207,13 +207,13 @@
|
||||
function storageMigrateAll(source,label){
|
||||
var sel=document.getElementById('migrate-target-'+source);
|
||||
var target=sel?sel.value:'';
|
||||
if(!target){ showAlert('Válassz céltárolót a legördülő menüből.'); return; }
|
||||
openDialog({title:'Összes adat áthelyezése', confirmLabel:'Áthelyezés',
|
||||
message:'Áthelyezed a(z) '+label+' ÖSSZES adatát ide: '+target+'?\n\nAz alkalmazások az áthelyezés alatt rövid időre leállnak. A forrás adatai csak az ellenőrzés és a sikeres újraindítás után törlődnek.',
|
||||
if(!target){ showAlert('{{T "storage.valassz_celtarolot_a_legordulo_menubol"}}'); return; }
|
||||
openDialog({title:'{{T "storage.osszes_adat_athelyezese"}}', confirmLabel:'{{T "storage.athelyezes"}}',
|
||||
message:'{{T "storage.athelyezed_a_z"}} '+label+' {{T "storage.osszes_adatat_ide"}} '+target+'{{T "storage.n_naz_alkalmazasok_az_athelyezes"}}',
|
||||
onConfirm:function(){
|
||||
fetch('/api/storage/migrate',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify({source:source,target:target})})
|
||||
.then(function(r){return r.json();}).then(function(d){ if(d.ok){ migWatch(); } else { showAlert('Hiba: '+(d.error||'ismeretlen')); } })
|
||||
.catch(function(e){ showAlert('Hiba: '+e); });
|
||||
.then(function(r){return r.json();}).then(function(d){ if(d.ok){ migWatch(); } else { showAlert('{{T "storage.hiba"}} '+(d.error||'{{T "storage.ismeretlen"}}')); } })
|
||||
.catch(function(e){ showAlert('{{T "storage.hiba"}} '+e); });
|
||||
}});
|
||||
}
|
||||
// Resume view: if a migration is STILL IN PROGRESS when the page loads, show the panel and watch.
|
||||
@@ -225,19 +225,19 @@
|
||||
</script>
|
||||
|
||||
<div style="margin-top:1rem;display:flex;gap:.75rem;flex-wrap:wrap">
|
||||
<a href="/storage/init" class="btn btn-sm btn-outline"><svg class="ico ico-sm"><use href="#i-plus"/></svg> Új meghajtó inicializálása</a>
|
||||
<a href="/storage/attach" class="btn btn-sm btn-outline"><svg class="ico ico-sm"><use href="#i-link"/></svg> Meglévő meghajtó csatolása</a>
|
||||
<a href="/storage/init" class="btn btn-sm btn-outline"><svg class="ico ico-sm"><use href="#i-plus"/></svg> {{T "storage.uj_meghajto_inicializalasa"}}</a>
|
||||
<a href="/storage/attach" class="btn btn-sm btn-outline"><svg class="ico ico-sm"><use href="#i-link"/></svg> {{T "storage.meglevo_meghajto_csatolasa"}}</a>
|
||||
</div>
|
||||
|
||||
<div id="agent-warn-note"></div>
|
||||
|
||||
<div style="margin-top:1.5rem" id="agent-unregistered-wrap" hidden>
|
||||
<div class="section-h"><h3>Nem regisztrált meghajtók</h3><span class="hint">az ügynök által észlelt, még nem regisztrált adatmeghajtók</span></div>
|
||||
<div class="section-h"><h3>{{T "storage.nem_regisztralt_meghajtok"}}</h3><span class="hint">{{T "storage.az_ugynok_altal_eszlelt_meg"}}</span></div>
|
||||
<div id="agent-unregistered" class="drive-list"></div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:1.5rem" id="agent-system-wrap" hidden>
|
||||
<div class="section-h"><h3>Rendszermeghajtók</h3><span class="hint">védett — csak operátori aláírással módosíthatók</span></div>
|
||||
<div class="section-h"><h3>{{T "storage.rendszermeghajtok"}}</h3><span class="hint">{{T "storage.vedett_csak_operatori_alairassal_modosit"}}</span></div>
|
||||
<div id="agent-system" class="drive-list"></div>
|
||||
</div>
|
||||
<div id="confirm-root"></div>
|
||||
@@ -255,16 +255,16 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
// was a misleading inconsistency. Hub-report ClassHint is UNCHANGED (UI-only suppression).
|
||||
if(d.type==='usb') return '';
|
||||
if(d.class==='fast') return '<span class="tag">gyors</span>';
|
||||
if(d.class==='slow') return '<span class="tag tag-off">lassú</span>';
|
||||
if(d.class==='slow') return '<span class="tag tag-off">{{T "storage.lassu"}}</span>';
|
||||
return '';
|
||||
}
|
||||
function roleTag(role){
|
||||
if(role==='system') return '<span class="tag">'+LOCK_ICO+'Rendszer — védett</span>';
|
||||
if(role==='backup') return '<span class="tag">'+LOCK_ICO+'Biztonsági mentés — védett</span>';
|
||||
if(role==='user-data') return '<span class="tag tag-run"><span class="dot"></span>Felhasználói adat</span>';
|
||||
return '<span class="tag">'+LOCK_ICO+'Védett</span>';
|
||||
if(role==='system') return '<span class="tag">'+LOCK_ICO+'{{T "storage.rendszer_vedett"}}</span>';
|
||||
if(role==='backup') return '<span class="tag">'+LOCK_ICO+'{{T "storage.biztonsagi_mentes_vedett"}}</span>';
|
||||
if(role==='user-data') return '<span class="tag tag-run"><span class="dot"></span>{{T "storage.felhasznaloi_adat"}}</span>';
|
||||
return '<span class="tag">'+LOCK_ICO+'{{T "storage.vedett"}}</span>';
|
||||
}
|
||||
function dataTag(d){ return d.data_bearing ? '<span class="tag tag-warn" title="'+esc(d.data_reason)+'">Adatot tartalmaz</span>' : ''; }
|
||||
function dataTag(d){ return d.data_bearing ? '<span class="tag tag-warn" title="'+esc(d.data_reason)+'">{{T "storage.adatot_tartalmaz"}}</span>' : ''; }
|
||||
// regKey is the path a drive is REGISTERED under: the STABLE intermediary path (guest_path,
|
||||
// /mnt/felhom-drives/<name>) the agent reports, else the raw mount_path (legacy). The registry
|
||||
// stores the STABLE path (handleStorageRegister/runStorageInit), so checking the raw mount_path
|
||||
@@ -272,23 +272,23 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
function regKey(d){ return d.guest_path || d.mount_path; }
|
||||
function regTag(d, registered){
|
||||
if(!d.mount_path) return '';
|
||||
return registered[regKey(d)] ? '<span class="tag tag-run"><span class="dot"></span>Regisztrálva</span>' : '<span class="tag tag-off"><span class="dot"></span>Nem regisztrált</span>';
|
||||
return registered[regKey(d)] ? '<span class="tag tag-run"><span class="dot"></span>{{T "storage.regisztralva"}}</span>' : '<span class="tag tag-off"><span class="dot"></span>{{T "storage.nem_regisztralt"}}</span>';
|
||||
}
|
||||
// appBackingTag marks the storages that actually hold deployed apps: the internal SSD (app
|
||||
// databases + Docker) and the external user-data drives (large app files). Keyed on the agent's
|
||||
// authoritative role/type — pure presentation, no agent contract change.
|
||||
function appBackingTag(d){
|
||||
if(d.type==='lvmthin') return '<span class="tag">Alkalmazás-rendszer</span>';
|
||||
if(d.role==='user-data') return '<span class="tag">Alkalmazás-adatok</span>';
|
||||
if(d.type==='lvmthin') return '<span class="tag">{{T "storage.alkalmazas_rendszer"}}</span>';
|
||||
if(d.role==='user-data') return '<span class="tag">{{T "storage.alkalmazas_adatok"}}</span>';
|
||||
return '';
|
||||
}
|
||||
// purposeDesc explains, in plain Hungarian, what each storage is for — so the "which one do the
|
||||
// apps use?" question is answered per-card. Keyed on type first, then role.
|
||||
function purposeDesc(d){
|
||||
if(d.type==='lvmthin') return 'Belső SSD — a szerver rendszere, a Docker és a telepített alkalmazások adatbázisai itt találhatók.';
|
||||
if(d.type==='local'||d.type==='dir') return 'Host tárhely — rendszer-sablonok, ISO-k, host szintű mentések. Nem tárol alkalmazásadatot.';
|
||||
if(d.type==='pbs'||d.role==='backup') return 'A biztonsági mentések tárhelye.';
|
||||
if(d.role==='user-data') return 'Külső adattároló — a telepített alkalmazások nagy méretű fájljai (média, dokumentumok) ide kerülnek. Más meghajtók biztonsági mentési céljaként is szolgálhat.';
|
||||
if(d.type==='lvmthin') return '{{T "storage.belso_ssd_a_szerver_rendszere"}}';
|
||||
if(d.type==='local'||d.type==='dir') return '{{T "storage.host_tarhely_rendszer_sablonok_iso"}}';
|
||||
if(d.type==='pbs'||d.role==='backup') return '{{T "storage.a_biztonsagi_mentesek_tarhelye"}}';
|
||||
if(d.role==='user-data') return '{{T "storage.kulso_adattarolo_a_telepitett_alkalmazas"}}';
|
||||
return '';
|
||||
}
|
||||
function capBar(d){
|
||||
@@ -310,14 +310,14 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
// agentWhere() AND deregister it from the registry (which stores the stable path). Posting the
|
||||
// raw path here would unmount the drive but leave the stable registry entry orphaned.
|
||||
if(!registered[regKey(d)]){
|
||||
btns += '<button class="btn btn-xs btn-primary" onclick="registerDrive(\''+mpRaw+'\')">Regisztrálás</button> ';
|
||||
btns += '<button class="btn btn-xs btn-primary" onclick="registerDrive(\''+mpRaw+'\')">{{T "storage.regisztralas"}}</button> ';
|
||||
}
|
||||
// Dedupe: if the registry card already offers "Biztonságos leválasztás" (USB safe-disconnect),
|
||||
// don't render the overlapping agent-level eject next to it — one detach affordance per card.
|
||||
if(!hasSafeDisconnect){
|
||||
btns += '<button class="btn btn-xs btn-danger-outline" onclick="confirmEject(\''+reg+'\')" title="A meghajtó lecsatolása és törlése a nyilvántartásból. Az adatok megmaradnak.">Leválasztás</button>';
|
||||
btns += '<button class="btn btn-xs btn-danger-outline" onclick="confirmEject(\''+reg+'\')" title="{{T "storage.lecsatolas_title"}}">{{T "storage.levalasztas"}}</button>';
|
||||
}
|
||||
if(d.backing_device){ btns += (btns?' ':'') + '<button class="btn btn-xs btn-danger-outline" onclick="confirmWipe(\''+dev+'\',\''+reg+'\')" title="A meghajtó formázása — a rajta lévő MINDEN adat véglegesen törlődik.">Formázás…</button>'; }
|
||||
if(d.backing_device){ btns += (btns?' ':'') + '<button class="btn btn-xs btn-danger-outline" onclick="confirmWipe(\''+dev+'\',\''+reg+'\')" title="{{T "storage.formazas_title"}}">{{T "storage.formazas"}}</button>'; }
|
||||
return btns ? '<div class="drive-actions">'+btns+'</div>' : '';
|
||||
}
|
||||
// Unified drive view (D1): the agent disk list ENRICHES the registry cards in place
|
||||
@@ -345,7 +345,7 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
var extra='<div class="metarows">'
|
||||
+'<span class="metarow">'+roleTag(d.role)+'</span>'
|
||||
+(d.class?'<span class="metarow">'+classTag(d)+'</span>':'')
|
||||
+(d.durable_id?'<span class="metarow mono" title="Tartós azonosító">'+esc(d.durable_id)+'</span>':'')
|
||||
+(d.durable_id?'<span class="metarow mono" title="{{T "storage.tartos_azonosito"}}">'+esc(d.durable_id)+'</span>':'')
|
||||
+'</div>'
|
||||
+actions(d,registered,hasSafeDisconnect);
|
||||
slot.innerHTML=extra;
|
||||
@@ -355,7 +355,7 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
var warn=document.getElementById('agent-warn-note');
|
||||
try{
|
||||
var r=await fetch('/api/disks'); var j=await r.json();
|
||||
if(!j.ok) throw new Error(j.error||'Nem elérhető');
|
||||
if(!j.ok) throw new Error(j.error||'{{T "storage.nem_elerheto"}}');
|
||||
var disks=(j.data&&j.data.disks)||[];
|
||||
var registered={}; (window.__registeredPaths||[]).forEach(function(p){registered[p]=true;});
|
||||
var sysHtml='', unregHtml='';
|
||||
@@ -372,7 +372,7 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
if(sysHtml){ document.getElementById('agent-system').innerHTML=sysHtml; sysWrap.hidden=false; }
|
||||
if(unregHtml){ document.getElementById('agent-unregistered').innerHTML=unregHtml; unregWrap.hidden=false; }
|
||||
}catch(e){
|
||||
if(warn) warn.innerHTML='<div class="alert alert-warning" style="margin-top:1rem">Az ügynök nem elérhető — élő meghajtóadatok nélkül.</div>';
|
||||
if(warn) warn.innerHTML='<div class="alert alert-warning" style="margin-top:1rem">{{T "storage.az_ugynok_nem_elerheto_elo"}}</div>';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,11 +387,11 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
var j=await r.json(); if(j.ok && j.data){ apps=j.data.apps||[]; copies=j.data.backup_copies||[]; }
|
||||
}catch(e){}
|
||||
var appsHtml = apps.length
|
||||
? '<p>A művelet után a következő alkalmazások <strong>nem fognak működni</strong>:</p><ul class="confirm-apps">'+apps.map(function(a){return '<li>'+esc(a)+'</li>';}).join('')+'</ul>'
|
||||
: '<p class="form-hint">Ehhez a meghajtóhoz jelenleg nincs telepített alkalmazás rendelve.</p>';
|
||||
? '<p>{{T "storage.a_muvelet_utan_a_kovetkezo"}}</p><ul class="confirm-apps">'+apps.map(function(a){return '<li>'+esc(a)+'</li>';}).join('')+'</ul>'
|
||||
: '<p class="form-hint">{{T "storage.ehhez_a_meghajtohoz_jelenleg_nincs"}}</p>';
|
||||
// P4 (4B): this drive may also hold cross-drive backup COPIES of other apps — a wipe removes them.
|
||||
var copiesHtml = copies.length
|
||||
? '<div class="alert alert-warning" style="margin-top:.5rem">Ez a meghajtó más alkalmazások <strong>biztonsági másolatait</strong> is tárolja — a törlés ezeket is eltávolítja:<ul class="confirm-apps">'+copies.map(function(a){return '<li>'+esc(a)+'</li>';}).join('')+'</ul><span class="form-hint">(A másolatok redundánsak — az eredetik a forrás-meghajtón maradnak.)</span></div>'
|
||||
? '<div class="alert alert-warning" style="margin-top:.5rem">{{T "storage.ez_a_meghajto_mas_alkalmazasok"}}<ul class="confirm-apps">'+copies.map(function(a){return '<li>'+esc(a)+'</li>';}).join('')+'</ul><span class="form-hint">{{T "storage.a_masolatok_redundansak_az_eredetik"}}</span></div>'
|
||||
: '';
|
||||
var root=document.getElementById('confirm-root');
|
||||
root.innerHTML='<div class="confirm-overlay" onclick="if(event.target===this)__closeConfirm()"><div class="confirm-box">'
|
||||
@@ -399,10 +399,10 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
+'<div class="alert alert-warning">'+esc(opts.danger)+'</div>'
|
||||
+appsHtml
|
||||
+copiesHtml
|
||||
+'<div class="confirm-input"><label>Megerősítéshez írja be a csatlakoztatási nevet: <strong class="mono">'+esc(opts.mountName)+'</strong></label>'
|
||||
+'<div class="confirm-input"><label>{{T "storage.megerositeshez_irja_be_a_csatlakoztatasi"}} <strong class="mono">'+esc(opts.mountName)+'</strong></label>'
|
||||
+'<input type="text" id="confirm-type" class="form-control" autocomplete="off" placeholder="'+esc(opts.mountName)+'" oninput="document.getElementById(\'confirm-go\').disabled=(this.value!==\''+esc(opts.mountName)+'\')"></div>'
|
||||
+'<div class="form-actions"><button id="confirm-go" class="btn btn-danger-outline" disabled>Megerősítés</button>'
|
||||
+'<button class="btn btn-outline" onclick="__closeConfirm()">Mégsem</button></div>'
|
||||
+'<div class="form-actions"><button id="confirm-go" class="btn btn-danger-outline" disabled>{{T "storage.megerosites"}}</button>'
|
||||
+'<button class="btn btn-outline" onclick="__closeConfirm()">{{T "storage.megsem"}}</button></div>'
|
||||
+'<div id="confirm-result" style="margin-top:.6rem"></div></div></div>';
|
||||
document.getElementById('confirm-go').onclick=opts.onConfirm;
|
||||
}
|
||||
@@ -412,37 +412,37 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
window.registerDrive=async function(where){
|
||||
try{
|
||||
var r=await fetch('/api/storage/register',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify({where:where})});
|
||||
var j=await r.json(); if(!j.ok){ showAlert('Regisztráció sikertelen: '+(j.error||'')); return; }
|
||||
var j=await r.json(); if(!j.ok){ showAlert('{{T "storage.regisztracio_sikertelen"}} '+(j.error||'')); return; }
|
||||
location.reload();
|
||||
}catch(e){ showAlert('Hiba: '+e.message); }
|
||||
}catch(e){ showAlert('{{T "storage.hiba"}} '+e.message); }
|
||||
};
|
||||
window.confirmEject=function(where){
|
||||
// The confirm name is the drive BASENAME (matches the server's path.Base(where) check); `where` may
|
||||
// be the stable /mnt/felhom-drives/<name> path, so strip the whole directory, not just the /mnt/ prefix.
|
||||
var name=where.split('/').filter(Boolean).pop()||where;
|
||||
openConfirm({title:'Meghajtó leválasztása', mount:where, mountName:name,
|
||||
danger:'A meghajtó leválasztásra kerül. Az adatok megmaradnak, de az ott tárolt alkalmazások elvesztik a tárhelyüket, amíg újra nem csatolja.',
|
||||
openConfirm({title:'{{T "storage.meghajto_levalasztasa"}}', mount:where, mountName:name,
|
||||
danger:'{{T "storage.a_meghajto_levalasztasra_kerul_az"}}',
|
||||
onConfirm:async function(){
|
||||
var out=document.getElementById('confirm-result'); out.innerHTML='<p class="form-hint">Leválasztás folyamatban…</p>';
|
||||
var out=document.getElementById('confirm-result'); out.innerHTML='<p class="form-hint">{{T "storage.levalasztas_folyamatban"}}</p>';
|
||||
try{
|
||||
var r=await fetch('/api/storage/eject',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify({where:where})});
|
||||
var j=await r.json(); if(!j.ok){ out.innerHTML='<div class="alert alert-error">Hiba: '+esc(j.error||'')+'</div>'; return; }
|
||||
var j=await r.json(); if(!j.ok){ out.innerHTML='<div class="alert alert-error">{{T "storage.hiba"}} '+esc(j.error||'')+'</div>'; return; }
|
||||
location.reload();
|
||||
}catch(e){ out.innerHTML='<div class="alert alert-error">Hiba: '+esc(e.message)+'</div>'; }
|
||||
}catch(e){ out.innerHTML='<div class="alert alert-error">{{T "storage.hiba"}} '+esc(e.message)+'</div>'; }
|
||||
}});
|
||||
};
|
||||
window.confirmWipe=function(device, where){
|
||||
// Basename (matches the server's path.Base(where) type-to-confirm check); `where` may be the stable path.
|
||||
var name=where.split('/').filter(Boolean).pop()||where;
|
||||
openConfirm({title:'Meghajtó törlése (formázás)', mount:where, mountName:name,
|
||||
danger:'FIGYELEM: a meghajtón lévő ÖSSZES ADAT véglegesen törlődik (formázás). Ez nem vonható vissza.',
|
||||
openConfirm({title:'{{T "storage.meghajto_torlese_formazas"}}', mount:where, mountName:name,
|
||||
danger:'{{T "storage.figyelem_a_meghajton_levo_osszes"}}',
|
||||
onConfirm:async function(){
|
||||
var out=document.getElementById('confirm-result'); out.innerHTML='<p class="form-hint">Törlés folyamatban…</p>';
|
||||
var out=document.getElementById('confirm-result'); out.innerHTML='<p class="form-hint">{{T "storage.torles_folyamatban"}}</p>';
|
||||
try{
|
||||
var r=await fetch('/api/storage/wipe',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify({device:device, where:where, mount_name:name})});
|
||||
var j=await r.json(); if(!j.ok){ out.innerHTML='<div class="alert alert-error">Hiba: '+esc(j.error||'')+'</div>'; return; }
|
||||
var j=await r.json(); if(!j.ok){ out.innerHTML='<div class="alert alert-error">{{T "storage.hiba"}} '+esc(j.error||'')+'</div>'; return; }
|
||||
location.reload();
|
||||
}catch(e){ out.innerHTML='<div class="alert alert-error">Hiba: '+esc(e.message)+'</div>'; }
|
||||
}catch(e){ out.innerHTML='<div class="alert alert-error">{{T "storage.hiba"}} '+esc(e.message)+'</div>'; }
|
||||
}});
|
||||
};
|
||||
load();
|
||||
@@ -450,25 +450,25 @@ window.__registeredPaths=[{{range .StoragePaths}}{{if .Path}}"{{.Path}}",{{end}}
|
||||
</script>
|
||||
|
||||
<details class="storage-add-details">
|
||||
<summary class="btn btn-sm btn-outline" style="margin-top:.75rem;cursor:pointer">Már csatlakoztatott tárhely hozzáadása kézzel</summary>
|
||||
<summary class="btn btn-sm btn-outline" style="margin-top:.75rem;cursor:pointer">{{T "storage.mar_csatlakoztatott_tarhely_hozzaadasa_k"}}</summary>
|
||||
<form method="POST" action="/settings/storage/add" class="storage-add-form">
|
||||
{{.CSRFField}}
|
||||
<div class="form-group">
|
||||
<label for="storage_path">Elérési út</label>
|
||||
<label for="storage_path">{{T "storage.eleresi_ut"}}</label>
|
||||
<input type="text" id="storage_path" name="storage_path" class="form-control"
|
||||
placeholder="/mnt/hdd_1" required>
|
||||
<span class="form-hint">Pl. /mnt/hdd_1 — a meghajtónak már csatolva kell lennie</span>
|
||||
<span class="form-hint">{{T "storage.pl_mnt_hdd_1_a"}}</span>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="storage_label">Megnevezés (opcionális)</label>
|
||||
<label for="storage_label">{{T "storage.megnevezes_opcionalis"}}</label>
|
||||
<input type="text" id="storage_label" name="storage_label" class="form-control"
|
||||
placeholder="Külső HDD 1TB">
|
||||
placeholder="{{T "storage.kulso_hdd_1tb"}}">
|
||||
</div>
|
||||
<label class="toggle" style="margin-bottom:1rem">
|
||||
<input type="checkbox" name="storage_default" value="true">
|
||||
<span class="toggle-label">Legyen alapértelmezett új telepítéseknél</span>
|
||||
<span class="toggle-label">{{T "storage.legyen_alapertelmezett_uj_telepiteseknel"}}</span>
|
||||
</label>
|
||||
<button type="submit" class="btn btn-primary">Hozzáadás</button>
|
||||
<button type="submit" class="btn btn-primary">{{T "storage.hozzaadas"}}</button>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
@@ -484,14 +484,14 @@ function openDialog(opts){
|
||||
if(!root) return;
|
||||
var typeGate=opts.typeToConfirm||'';
|
||||
var html='<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>'
|
||||
+'<h3>'+escText(opts.title||'{{T "storage.megerosites"}}')+'</h3>'
|
||||
+'<p style="white-space:pre-line">'+escText(opts.message||'')+'</p>';
|
||||
if(typeGate){
|
||||
html+='<div class="confirm-input"><label>Megerősítéshez írja be: <strong class="mono">'+escText(typeGate)+'</strong></label>'
|
||||
html+='<div class="confirm-input"><label>{{T "storage.megerositeshez_irja_be"}} <strong class="mono">'+escText(typeGate)+'</strong></label>'
|
||||
+'<input type="text" id="dialog-type" class="form-control" autocomplete="off" placeholder="'+escText(typeGate)+'"></div>';
|
||||
}
|
||||
html+='<div class="form-actions"><button id="dialog-go" class="btn '+(typeGate?'btn-danger-outline':'btn-primary')+'"'+(typeGate?' disabled':'')+'>'+escText(opts.confirmLabel||'Megerősítés')+'</button>'
|
||||
+'<button type="button" class="btn btn-outline" id="dialog-cancel">Mégsem</button></div>'
|
||||
html+='<div class="form-actions"><button id="dialog-go" class="btn '+(typeGate?'btn-danger-outline':'btn-primary')+'"'+(typeGate?' disabled':'')+'>'+escText(opts.confirmLabel||'{{T "storage.megerosites"}}')+'</button>'
|
||||
+'<button type="button" class="btn btn-outline" id="dialog-cancel">{{T "storage.megsem"}}</button></div>'
|
||||
+'</div></div>';
|
||||
root.innerHTML=html;
|
||||
var go=document.getElementById('dialog-go');
|
||||
@@ -504,7 +504,7 @@ function openDialog(opts){
|
||||
// Overlay-confirmed POST form submit (registry drive-remove forms).
|
||||
function storageRemoveDialog(ev, form, msg){
|
||||
ev.preventDefault();
|
||||
openDialog({title:'Meghajtó eltávolítása', message:msg, confirmLabel:'Eltávolítás', onConfirm:function(){ form.submit(); }});
|
||||
openDialog({title:'{{T "storage.meghajto_eltavolitasa"}}', message:msg, confirmLabel:'{{T "storage.eltavolitas"}}', onConfirm:function(){ form.submit(); }});
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -522,10 +522,10 @@ function editStorageLabel(path, currentLabel) {
|
||||
wrap.querySelector('input[name=storage_label]').focus();
|
||||
}
|
||||
function storageDisconnect(path, label, appCount) {
|
||||
var msg = 'Biztos leválasztja a meghajtót: ' + label + '?';
|
||||
if (appCount > 0) msg += '\n\nA rajta futó ' + appCount + ' alkalmazás le fog állni.';
|
||||
msg += '\n\nA meghajtó ezután biztonságosan eltávolítható.';
|
||||
openDialog({title:'Meghajtó leválasztása', message:msg, confirmLabel:'Leválasztás', onConfirm:function(){ doStorageDisconnect(path); }});
|
||||
var msg = '{{T "storage.biztos_levalasztja_a_meghajtot"}} ' + label + '?';
|
||||
if (appCount > 0) msg += '{{T "storage.n_na_rajta_futo"}} ' + appCount + ' {{T "storage.alkalmazas_le_fog_allni"}}';
|
||||
msg += '{{T "storage.n_na_meghajto_ezutan_biztonsagosan"}}';
|
||||
openDialog({title:'{{T "storage.meghajto_levalasztasa"}}', message:msg, confirmLabel:'{{T "storage.levalasztas"}}', onConfirm:function(){ doStorageDisconnect(path); }});
|
||||
}
|
||||
function doStorageDisconnect(path) {
|
||||
fetch('/api/storage/disconnect', {
|
||||
@@ -534,16 +534,16 @@ function doStorageDisconnect(path) {
|
||||
body: JSON.stringify({where: path})
|
||||
}).then(function(r) { return r.json(); }).then(function(data) {
|
||||
if (data.ok) {
|
||||
showAlert('A meghajtó biztonságosan eltávolítható.');
|
||||
showAlert('{{T "storage.a_meghajto_biztonsagosan_eltavolithato"}}');
|
||||
location.reload();
|
||||
} else {
|
||||
showAlert('Hiba: ' + (data.error || 'ismeretlen'));
|
||||
showAlert('{{T "storage.hiba"}} ' + (data.error || '{{T "storage.ismeretlen"}}'));
|
||||
}
|
||||
}).catch(function(e) { showAlert('Hiba: ' + e); });
|
||||
}).catch(function(e) { showAlert('{{T "storage.hiba"}} ' + e); });
|
||||
}
|
||||
function storageReconnect(path) {
|
||||
var actionsDiv = document.getElementById('storage-actions-' + path);
|
||||
if (actionsDiv) actionsDiv.innerHTML = '<span class="form-hint">Csatlakoztatás...</span>';
|
||||
if (actionsDiv) actionsDiv.innerHTML = '<span class="form-hint">{{T "storage.csatlakoztatas_2"}}</span>';
|
||||
fetch('/api/storage/reconnect', {
|
||||
method: 'POST',
|
||||
headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()),
|
||||
@@ -552,12 +552,12 @@ function storageReconnect(path) {
|
||||
if (data.ok) {
|
||||
location.reload();
|
||||
} else {
|
||||
showAlert('Hiba: ' + (data.error || 'ismeretlen'));
|
||||
if (actionsDiv) actionsDiv.innerHTML = '<button class="btn btn-xs btn-primary" onclick="storageReconnect(\'' + path + '\')">Csatlakoztatás</button>';
|
||||
showAlert('{{T "storage.hiba"}} ' + (data.error || '{{T "storage.ismeretlen"}}'));
|
||||
if (actionsDiv) actionsDiv.innerHTML = '<button class="btn btn-xs btn-primary" onclick="storageReconnect(\'' + path + '\')">{{T "storage.csatlakoztatas"}}</button>';
|
||||
}
|
||||
}).catch(function(e) {
|
||||
showAlert('Hiba: ' + e);
|
||||
if (actionsDiv) actionsDiv.innerHTML = '<button class="btn btn-xs btn-primary" onclick="storageReconnect(\'' + path + '\')">Csatlakoztatás</button>';
|
||||
showAlert('{{T "storage.hiba"}} ' + e);
|
||||
if (actionsDiv) actionsDiv.innerHTML = '<button class="btn btn-xs btn-primary" onclick="storageReconnect(\'' + path + '\')">{{T "storage.csatlakoztatas"}}</button>';
|
||||
});
|
||||
}
|
||||
function storageRestartApps(path) {
|
||||
@@ -568,12 +568,12 @@ function storageRestartApps(path) {
|
||||
}).then(function(r) { return r.json(); }).then(function(data) {
|
||||
if (data.ok) {
|
||||
var r2 = data.restarted || [];
|
||||
if (r2.length) showAlert('Elindítva: ' + r2.join(', '));
|
||||
if (r2.length) showAlert('{{T "storage.elinditva"}} ' + r2.join(', '));
|
||||
location.reload();
|
||||
} else {
|
||||
showAlert('Hiba: ' + (data.error || 'ismeretlen'));
|
||||
showAlert('{{T "storage.hiba"}} ' + (data.error || '{{T "storage.ismeretlen"}}'));
|
||||
}
|
||||
}).catch(function(e) { showAlert('Hiba: ' + e); });
|
||||
}).catch(function(e) { showAlert('{{T "storage.hiba"}} ' + e); });
|
||||
}
|
||||
// H2: decommission a drive (non-destructive). If a migrate target is picked in the inline select →
|
||||
// migrate-then-decommission; otherwise decommission-anyway with type-to-confirm.
|
||||
@@ -581,14 +581,14 @@ function storageDecommission(path, label, appCount) {
|
||||
var sel = document.getElementById('migrate-target-' + path);
|
||||
var target = sel ? sel.value : '';
|
||||
if (target) {
|
||||
openDialog({title:'Leszerelés áthelyezéssel', confirmLabel:'Leszerelés',
|
||||
message:'Leszerelés áthelyezéssel: minden adat átmásolása ide: ' + target + ', majd a(z) ' + label + ' leszerelése?\n\nAz adatok NEM törlődnek.',
|
||||
openDialog({title:'{{T "storage.leszereles_athelyezessel"}}', confirmLabel:'{{T "storage.leszereles"}}',
|
||||
message:'{{T "storage.leszereles_athelyezessel_minden_adat_atm"}} ' + target + ', {{T "storage.majd_a_z"}} ' + label + ' {{T "storage.leszerelese_n_naz_adatok_nem"}}',
|
||||
onConfirm:function(){ doStorageDecommission({where: path, mode: 'migrate', target: target}); }});
|
||||
} else {
|
||||
var name = path.split('/').pop();
|
||||
openDialog({title:'Meghajtó leszerelése', confirmLabel:'Leszerelés', typeToConfirm:name,
|
||||
message:'A(z) ' + label + ' leszereléséhez (áthelyezés nélkül) írja be a meghajtó nevét megerősítésként.' +
|
||||
(appCount > 0 ? '\n\nFIGYELEM: ' + appCount + ' alkalmazás leáll (az adatok megmaradnak).' : ''),
|
||||
openDialog({title:'{{T "storage.meghajto_leszerelese"}}', confirmLabel:'{{T "storage.leszereles"}}', typeToConfirm:name,
|
||||
message:'{{T "storage.a_z"}} ' + label + ' {{T "storage.leszerelesehez_athelyezes_nelkul_irja_be"}}' +
|
||||
(appCount > 0 ? '\n\n{{T "storage.figyelem"}} ' + appCount + ' {{T "storage.alkalmazas_leall_az_adatok_megmaradnak"}}' : ''),
|
||||
onConfirm:function(){ doStorageDecommission({where: path, mode: 'anyway', mount_name: name}); }});
|
||||
}
|
||||
}
|
||||
@@ -598,15 +598,15 @@ function doStorageDecommission(body) {
|
||||
headers: Object.assign({'Content-Type': 'application/json'}, csrfHeaders()),
|
||||
body: JSON.stringify(body)
|
||||
}).then(function(r) { return r.json(); }).then(function(data) {
|
||||
if (data.ok) { showAlert('Leszerelés elindítva.'); location.reload(); }
|
||||
else { showAlert('Hiba: ' + (data.error || 'ismeretlen')); }
|
||||
}).catch(function(e) { showAlert('Hiba: ' + e); });
|
||||
if (data.ok) { showAlert('{{T "storage.leszereles_elinditva"}}'); location.reload(); }
|
||||
else { showAlert('{{T "storage.hiba"}} ' + (data.error || '{{T "storage.ismeretlen"}}')); }
|
||||
}).catch(function(e) { showAlert('{{T "storage.hiba"}} ' + e); });
|
||||
}
|
||||
// H3: one-click re-enroll a decommissioned/ejected drive — clears the marker, re-attaches under the
|
||||
// parent, restarts the gate-stopped apps (data is intact).
|
||||
function storageReEnroll(path, label) {
|
||||
openDialog({title:'Visszacsatlakoztatás', confirmLabel:'Visszacsatlakoztatás',
|
||||
message:'Visszacsatlakoztatja a(z) ' + label + ' meghajtót?\n\nAz adatok érintetlenek; a leállított alkalmazások újraindulnak.',
|
||||
openDialog({title:'{{T "storage.visszacsatlakoztatas"}}', confirmLabel:'{{T "storage.visszacsatlakoztatas"}}',
|
||||
message:'{{T "storage.visszacsatlakoztatja_a_z"}} ' + label + ' {{T "storage.meghajtot_n_naz_adatok_erintetlenek"}}',
|
||||
onConfirm:function(){ doStorageReEnroll(path); }});
|
||||
}
|
||||
function doStorageReEnroll(path) {
|
||||
@@ -616,8 +616,8 @@ function doStorageReEnroll(path) {
|
||||
body: JSON.stringify({where: path})
|
||||
}).then(function(r) { return r.json(); }).then(function(data) {
|
||||
if (data.ok) { location.reload(); }
|
||||
else { showAlert('Hiba: ' + (data.error || 'ismeretlen')); }
|
||||
}).catch(function(e) { showAlert('Hiba: ' + e); });
|
||||
else { showAlert('{{T "storage.hiba"}} ' + (data.error || '{{T "storage.ismeretlen"}}')); }
|
||||
}).catch(function(e) { showAlert('{{T "storage.hiba"}} ' + e); });
|
||||
}
|
||||
function cancelEditLabel(path, label) {
|
||||
var wrap = document.getElementById('label-wrap-' + path);
|
||||
@@ -630,7 +630,7 @@ function cancelEditLabel(path, label) {
|
||||
span.textContent = label;
|
||||
var btn = document.createElement('button');
|
||||
btn.className = 'btn btn-xs btn-ghost';
|
||||
btn.setAttribute('title', 'Átnevezés');
|
||||
btn.setAttribute('title', '{{T "storage.atnevezes"}}');
|
||||
btn.innerHTML = '<svg class="ico ico-sm"><use href="#i-pencil"/></svg>';
|
||||
btn.addEventListener('click', function() { editStorageLabel(path, label); });
|
||||
wrap.appendChild(span);
|
||||
|
||||
Reference in New Issue
Block a user