ac149c2aa4
- 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
233 lines
14 KiB
HTML
233 lines
14 KiB
HTML
{{define "storage_network"}}
|
|
{{template "layout_start" .}}
|
|
|
|
<div class="page-header">
|
|
<div style="display:flex;align-items:center;gap:.5rem">
|
|
<a href="/settings" class="btn btn-sm btn-outline">{{T "storage_network.vissza"}}</a>
|
|
<h2>{{T "storage_network.tarhely_halozati_tarhely_nas"}}</h2>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<!-- NAS network storage (Part A2) — a distinct class from the physical drives. No
|
|
leválasztás/leszerelés/áthelyezés/törlés; the only lifecycle action is Eltávolítás. -->
|
|
<h3>{{T "storage_network.nas_megosztasok"}}</h3>
|
|
<p class="settings-card-desc">
|
|
{{T "storage_network.egy_nas_megosztas_nfs_vagy"}}
|
|
</p>
|
|
{{if .NetworkStoragePaths}}
|
|
<div class="storage-paths-list">
|
|
{{range .NetworkStoragePaths}}
|
|
<div class="storage-path-item{{if or (eq .Health "unreachable") (eq .Health "stub")}} storage-disconnected{{end}}">
|
|
<div class="storage-path-header">
|
|
<div class="storage-path-info">
|
|
<span class="storage-path-label">{{.Label}}</span>
|
|
<span class="storage-path-path mono">{{.Protocol}} · {{.Server}}:{{.Export}} → {{.Path}}</span>
|
|
{{if .Orphan}}<span class="form-hint">{{T "storage_network.a_megosztas_be_van_allitva"}}</span>{{end}}
|
|
</div>
|
|
<div class="storage-path-badges">
|
|
{{if .Orphan}}<span class="badge badge-warn" title="{{T "storage_network.beallitva_a_gazdagepen_de_nincs"}}">{{T "storage_network.arva"}}</span>
|
|
{{else if eq .Health "ok"}}<span class="badge badge-ok" title="{{T "storage_network.a_megosztas_elerheto_es_csatlakoztatva"}}">{{T "storage_network.elerheto"}}</span>
|
|
{{else if eq .Health "idle"}}<span class="badge badge-neutral" title="{{T "storage_network.elerheto_jelenleg_keszenletben_igeny_sze"}}">{{T "storage_network.keszenlet"}}</span>
|
|
{{else if eq .Health "stub"}}<span class="badge badge-warn" title="{{T "storage_network.a_megosztas_a_gazdagepen_elerheto"}}">{{T "storage_network.hibas_az_alkalmazasok_nem_a"}}</span>
|
|
{{else if eq .Health "unreachable"}}<span class="badge badge-warn" title="{{T "storage_network.a_nas_jelenleg_nem_erheto"}}">{{T "storage_network.nem_elerheto"}}</span>
|
|
{{else}}<span class="badge badge-neutral" title="{{T "storage_network.az_allapot_jelenleg_nem_lekerdezheto"}}">{{T "storage_network.ismeretlen"}}</span>{{end}}
|
|
</div>
|
|
</div>
|
|
<div class="storage-path-actions">
|
|
<button class="btn btn-xs btn-danger-outline" onclick="netStorageRemove('{{.Name}}','{{.Label}}')">{{T "storage_network.eltavolitas"}}</button>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
</div>
|
|
{{else}}
|
|
<p class="form-hint">{{T "storage_network.nincs_halozati_tarhely_beallitva"}}</p>
|
|
{{end}}
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<h3>{{T "storage_network.halozati_tarhely_hozzaadasa"}}</h3>
|
|
{{if eq .NetAddSupport "no"}}
|
|
<!-- Capability gate (agent predates the verify-before-commit add semantics): the add form is
|
|
withheld; the share list + remove above stay fully usable. -->
|
|
<div class="alert alert-warning">{{T "storage_network.a_rendszer_hatterszolgaltatasa_ugynok_re"}}</div>
|
|
{{else}}
|
|
<p class="settings-card-desc">{{T "storage_network.a_csatlakoztatas_elott_a_rendszer"}}</p>
|
|
<form id="ns-add-form" onsubmit="return netStorageAdd(event)">
|
|
<div class="form-group">
|
|
<label for="ns-protocol">{{T "storage_network.protokoll"}}</label>
|
|
<select id="ns-protocol" class="form-control" onchange="nsToggleSmb()">
|
|
<option value="smb">{{T "storage_network.smb_synology_qnap_a_legtobb"}}</option>
|
|
<option value="nfs">NFS (TrueNAS, Linux szerver)</option>
|
|
</select>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="ns-name">{{T "storage_network.nev_azonosito"}} <span class="required">*</span></label>
|
|
<input id="ns-name" type="text" class="form-control" placeholder="{{T "storage_network.pl_media"}}"
|
|
pattern="[a-zA-Z0-9_-]+" required style="max-width:220px">
|
|
<span class="form-hint">{{T "storage_network.a_megosztas_a_mnt_felhom"}}</span>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="ns-server">{{T "storage_network.szerver_ip_vagy_hosztnev"}} <span class="required">*</span></label>
|
|
<input id="ns-server" type="text" class="form-control" placeholder="{{T "storage_network.pl_192_168_0_10"}}" required style="max-width:220px">
|
|
<span class="form-hint">{{T "storage_network.ip_cim_vagy_dns_nev"}}</span>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="ns-export" id="ns-export-label">{{T "storage_network.megosztas_neve"}}</label>
|
|
<input id="ns-export" type="text" class="form-control" placeholder="{{T "storage_network.pl_media"}}" required style="max-width:320px">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="ns-uid">{{T "storage_network.alkalmazas_felhasznaloi_azonosito_uid"}}</label>
|
|
<input id="ns-uid" type="number" value="1000" class="form-control" style="max-width:120px" oninput="nsUpdateHostID()">
|
|
<span class="form-hint">{{T "storage_network.a_legtobb_mediaalkalmazas_1000_es"}}</span>
|
|
</div>
|
|
<div id="ns-smb-creds">
|
|
<div class="form-group">
|
|
<label for="ns-username">{{T "storage_network.smb_felhasznalonev"}} <span class="required">*</span></label>
|
|
<input id="ns-username" type="text" autocomplete="off" class="form-control" style="max-width:220px">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="ns-password">{{T "storage_network.smb_jelszo"}} <span class="required">*</span></label>
|
|
<input id="ns-password" type="password" autocomplete="new-password" class="form-control" style="max-width:220px">
|
|
<span class="form-hint">{{T "storage_network.a_jelszot_a_gazda_ugynok"}}</span>
|
|
</div>
|
|
</div>
|
|
<div class="form-actions" style="gap:.75rem">
|
|
<button type="submit" class="btn btn-primary" id="ns-add-btn">{{T "storage_network.csatlakoztatas"}}</button>
|
|
</div>
|
|
<div id="ns-add-result" style="margin-top:1rem"></div>
|
|
</form>
|
|
{{end}}
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<h3>{{T "storage_network.mit_kell_beallitani_a_nas"}}</h3>
|
|
<details>
|
|
<summary>{{T "storage_network.utmutato_megjelenitese"}}</summary>
|
|
<p>{{T "storage_network.engedelyezze_a_felhom_gep_ip"}}</p>
|
|
<h4>{{T "storage_network.smb_synology_qnap_a_legtobb"}}</h4>
|
|
<p>{{T "storage_network.hozzon_letre_vagy_jeloljon_ki"}}</p>
|
|
<h4>NFS</h4>
|
|
<p>{{T "storage_network.synology_dsm_ellenorzott_lepesek_eloszor"}}</p>
|
|
<p>{{T "storage_network.egyszeru_mas_nas_okhoz_kapcsolja"}}</p>
|
|
<p>{{T "storage_network.teljes_erteku_truenas_linux_szerver"}}
|
|
<code class="mono">rw,all_squash,anonuid=<span class="ns-hostid">101000</span>,anongid=<span class="ns-hostid">101000</span></code>
|
|
{{T "storage_network.igy_a_tulajdonos_informaciok_is"}}</p>
|
|
<p class="form-hint">{{T "storage_network.a_qnap_feluletere_szabott_lepesrol"}}</p>
|
|
</details>
|
|
</div>
|
|
|
|
<script>
|
|
function nsToggleSmb(){
|
|
var smb = document.getElementById('ns-protocol').value === 'smb';
|
|
document.getElementById('ns-smb-creds').style.display = smb ? 'block' : 'none';
|
|
document.getElementById('ns-export-label').textContent = smb ? '{{T "storage_network.megosztas_neve"}}' : '{{T "storage_network.megosztas_nfs_export_utvonal"}}';
|
|
document.getElementById('ns-export').placeholder = smb ? '{{T "storage_network.pl_media"}}' : '{{T "storage_network.pl_volume1_media"}}';
|
|
document.getElementById('ns-username').required = smb;
|
|
document.getElementById('ns-password').required = smb;
|
|
}
|
|
function nsUpdateHostID(){
|
|
var uid = parseInt(document.getElementById('ns-uid').value||'1000',10);
|
|
if(isNaN(uid) || uid < 0){ uid = 1000; }
|
|
document.querySelectorAll('.ns-hostid').forEach(function(el){ el.textContent = String(uid + 100000); });
|
|
}
|
|
function nsEsc(s){ return String(s==null?'':s).replace(/[&<>"]/g,function(c){return {'&':'&','<':'<','>':'>','"':'"'}[c];}); }
|
|
|
|
// Poll-driven progress: the add starts a server-side verify job; we poll its status and show the
|
|
// staged Hungarian text until a terminal phase.
|
|
var nsPhaseText = {
|
|
agent_add: '{{T "storage_network.kapcsolodas_a_szerverhez"}}',
|
|
verifying: '{{T "storage_network.csatolasi_teszt"}}',
|
|
probing: '{{T "storage_network.irasteszt"}}',
|
|
registering: '{{T "storage_network.regisztralas"}}'
|
|
};
|
|
var nsPollTimer = null;
|
|
|
|
function netStorageAdd(ev){
|
|
ev.preventDefault();
|
|
var btn = document.getElementById('ns-add-btn');
|
|
var out = document.getElementById('ns-add-result');
|
|
var uid = parseInt(document.getElementById('ns-uid').value||'1000',10);
|
|
var body = {
|
|
name: (document.getElementById('ns-name').value||'').trim(),
|
|
protocol: document.getElementById('ns-protocol').value,
|
|
server: (document.getElementById('ns-server').value||'').trim(),
|
|
export: (document.getElementById('ns-export').value||'').trim(),
|
|
mapped_uid: uid,
|
|
mapped_gid: uid,
|
|
username: (document.getElementById('ns-username').value||''),
|
|
password: (document.getElementById('ns-password').value||'')
|
|
};
|
|
btn.disabled = true;
|
|
out.innerHTML = '<p class="form-hint">' + nsPhaseText.agent_add + '</p>';
|
|
fetch('/api/storage/netstorage/add',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify(body)})
|
|
.then(function(r){return r.json();}).then(function(d){
|
|
if(!d.ok){ nsShowError((d.error||'{{T "storage_network.ismeretlen_hiba"}}'), ''); btn.disabled=false; return; }
|
|
nsPollTimer = setInterval(nsPollStatus, 1500);
|
|
}).catch(function(e){ nsShowError(String(e), ''); btn.disabled=false; });
|
|
return false;
|
|
}
|
|
|
|
function nsPollStatus(){
|
|
fetch('/api/storage/netstorage/add/status')
|
|
.then(function(r){return r.json();}).then(function(d){
|
|
var st = (d.data||{});
|
|
var out = document.getElementById('ns-add-result');
|
|
if(st.phase === 'done'){
|
|
clearInterval(nsPollTimer);
|
|
var warn = st.warn ? ' <span class="form-hint">(' + nsEsc(st.warn) + ')</span>' : '';
|
|
out.innerHTML = '<div class="alert alert-success">{{T "storage_network.a_halozati_tarhely_sikeresen_csatlakozta"}} <strong class="mono">' + nsEsc(st.path||'') + '</strong>.' + warn + '</div>';
|
|
setTimeout(function(){ location.reload(); }, 1500);
|
|
} else if(st.phase === 'failed'){
|
|
clearInterval(nsPollTimer);
|
|
nsShowError(st.message || '{{T "storage_network.a_csatolas_sikertelen"}}', st.detail || '');
|
|
document.getElementById('ns-add-btn').disabled = false;
|
|
} else if(nsPhaseText[st.phase]){
|
|
out.innerHTML = '<p class="form-hint">' + nsPhaseText[st.phase] + '</p>';
|
|
}
|
|
}).catch(function(){ /* transient poll error — keep polling */ });
|
|
}
|
|
|
|
function nsShowError(message, detail){
|
|
var out = document.getElementById('ns-add-result');
|
|
var html = '<div class="alert alert-error">' + nsEsc(message);
|
|
if(detail){
|
|
html += '<details class="mono" style="margin-top:.5rem"><summary>{{T "storage_network.technikai_reszletek"}}</summary><p style="white-space:pre-wrap">' + nsEsc(detail) + '</p></details>';
|
|
}
|
|
html += '</div>';
|
|
out.innerHTML = html;
|
|
}
|
|
|
|
function netStorageRemove(name,label){
|
|
openDialog({title:'{{T "storage_network.halozati_tarhely_eltavolitasa"}}', confirmLabel:'{{T "storage_network.eltavolitas"}}',
|
|
message:'{{T "storage_network.biztosan_eltavolitja_a_z"}} '+label+' {{T "storage_network.halozati_tarhelyet_n_na_megosztas"}}',
|
|
onConfirm:function(){
|
|
fetch('/api/storage/netstorage/remove',{method:'POST',headers:Object.assign({'Content-Type':'application/json'},csrfHeaders()),body:JSON.stringify({name:name})})
|
|
.then(function(r){return r.json();}).then(function(d){
|
|
if(d.ok){ location.reload(); } else { showAlert('{{T "storage_network.hiba"}} '+(d.error||'{{T "storage_network.ismeretlen_2"}}')); }
|
|
}).catch(function(e){ showAlert('{{T "storage_network.hiba"}} '+e); });
|
|
}});
|
|
}
|
|
if(document.getElementById('ns-add-form')){ nsToggleSmb(); nsUpdateHostID(); } // form absent on the capability banner
|
|
</script>
|
|
<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 "storage_network.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 "storage_network.megerosites"}}')+'</button>'
|
|
+'<button type="button" class="btn btn-outline" id="dialog-cancel">{{T "storage_network.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(); };
|
|
}
|
|
</script>
|
|
{{template "layout_end" .}}
|
|
{{end}}
|