98834dd7e8
New Settings wizard to attach drives with existing filesystems without formatting. Mounts partition at staging path, lets user browse and pick a subfolder, then bind-mounts it at /mnt/<name> with fstab entries. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
313 lines
16 KiB
HTML
313 lines
16 KiB
HTML
{{define "settings"}}
|
||
{{template "layout_start" .}}
|
||
|
||
<div class="page-header">
|
||
<h2>Beállítások</h2>
|
||
</div>
|
||
|
||
<!-- Section A: System Configuration (read-only) -->
|
||
<div class="settings-card">
|
||
<h3>Rendszer konfiguráció</h3>
|
||
<p class="settings-card-desc">Az üzemeltető által beállított értékek. Módosításhoz kérd az üzemeltetőt.</p>
|
||
<div class="settings-grid">
|
||
<div class="settings-row">
|
||
<span class="settings-label">Ügyfél azonosító</span>
|
||
<span class="settings-value mono">{{.CustomerID}}</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<span class="settings-label">Ügyfél neve</span>
|
||
<span class="settings-value">{{.CustomerName}}</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<span class="settings-label">Domain</span>
|
||
<span class="settings-value mono">{{.CustomerDomain}}</span>
|
||
</div>
|
||
{{if .GitRepoURL}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">Alkalmazás sablon forrás</span>
|
||
<span class="settings-value mono settings-value-truncate">{{.GitRepoURL}}</span>
|
||
</div>
|
||
{{end}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">Sablon szinkronizálás</span>
|
||
<span class="settings-value mono">{{.GitSyncInterval}}</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<span class="settings-label">Biztonsági mentés</span>
|
||
<span class="settings-value">{{if .BackupEnabled}}<span class="state-text-green">✅ Aktív</span>{{else}}<span class="state-text-red">❌ Inaktív</span>{{end}}</span>
|
||
</div>
|
||
{{if .BackupEnabled}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">Mentés ütemezés</span>
|
||
<span class="settings-value mono">{{.DBDumpSchedule}} / {{.ResticSchedule}}</span>
|
||
</div>
|
||
{{end}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">Monitoring</span>
|
||
<span class="settings-value">{{if .MonitoringEnabled}}<span class="state-text-green">✅ Aktív</span>{{else}}<span class="state-text-red">❌ Inaktív</span>{{end}}</span>
|
||
</div>
|
||
{{if .MonitoringEnabled}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">Healthchecks URL</span>
|
||
<span class="settings-value mono settings-value-truncate">{{if .HealthchecksBase}}{{.HealthchecksBase}}{{else}}–{{end}}</span>
|
||
</div>
|
||
{{end}}
|
||
<div class="settings-row">
|
||
<span class="settings-label">Hub jelentés</span>
|
||
<span class="settings-value">{{if .HubEnabled}}<span class="state-text-green">✅ Aktív</span>{{else}}–{{end}}</span>
|
||
</div>
|
||
<div class="settings-row">
|
||
<span class="settings-label">Controller verzió</span>
|
||
<span class="settings-value mono">{{.Version}}</span>
|
||
</div>
|
||
</div>
|
||
</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>
|
||
|
||
{{if .StorageError}}<div class="alert alert-error">{{.StorageError}}</div>{{end}}
|
||
{{if .StorageSuccess}}<div class="alert alert-info">{{.StorageSuccess}}</div>{{end}}
|
||
|
||
{{if .StoragePaths}}
|
||
<div class="storage-paths-list">
|
||
{{range .StoragePaths}}
|
||
<div class="storage-path-item">
|
||
<div class="storage-path-header">
|
||
<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>
|
||
<button class="btn btn-xs btn-ghost" onclick="editStorageLabel('{{.Path}}', '{{.Label}}')" title="Átnevezés">✏️</button>
|
||
</div>
|
||
<span class="storage-path-path mono">{{.Path}}</span>
|
||
</div>
|
||
<div class="storage-path-badges">
|
||
{{if .IsDefault}}<span class="badge state-green">Alapértelmezett</span>{{end}}
|
||
{{if .Schedulable}}<span class="badge" style="background:rgba(0,136,204,0.15);color:var(--accent-light)">Aktív</span>{{else}}<span class="badge state-gray">Inaktív</span>{{end}}
|
||
{{if not .IsMounted}}<span class="badge badge-warn">Rendszermeghajtón</span>{{end}}
|
||
</div>
|
||
</div>
|
||
<div class="storage-path-details">
|
||
{{if .DiskInfo}}
|
||
<div class="storage-path-disk">
|
||
<div class="system-info-header">
|
||
<span class="system-info-value">{{.DiskInfo.UsedHuman}} / {{.DiskInfo.TotalHuman}}</span>
|
||
</div>
|
||
<div class="system-bar">
|
||
<div class="system-bar-fill {{if ge .DiskInfo.UsedPercent 90.0}}system-bar-red{{else if ge .DiskInfo.UsedPercent 70.0}}system-bar-yellow{{else}}system-bar-green{{end}}"
|
||
style="width:{{printf "%.0f" .DiskInfo.UsedPercent}}%"></div>
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
{{if .FSInfo}}
|
||
<div class="storage-path-fsinfo mono form-hint">
|
||
{{.FSInfo.FSType}} · {{.FSInfo.Device}}{{if .FSInfo.Model}} · {{.FSInfo.Model}}{{end}}
|
||
</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
|
||
</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}}
|
||
<a href="/stacks/{{.Stack}}/migrate" class="btn btn-xs btn-outline" title="Adatok áthelyezése másik tárolóra">📦 Mozgatás</a>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
</details>
|
||
{{else}}
|
||
<span class="form-hint">Nincs alkalmazás ezen a tárolón</span>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
<div class="storage-path-actions">
|
||
{{if not .IsDefault}}
|
||
<form method="POST" action="/settings/storage/default" style="display:inline">
|
||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||
<button type="submit" class="btn btn-xs btn-outline">Legyen alapértelmezett</button>
|
||
</form>
|
||
{{end}}
|
||
{{if .Schedulable}}
|
||
<form method="POST" action="/settings/storage/schedulable" style="display:inline">
|
||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||
<input type="hidden" name="schedulable" value="false">
|
||
<button type="submit" class="btn btn-xs btn-outline">Letiltás</button>
|
||
</form>
|
||
{{else}}
|
||
<form method="POST" action="/settings/storage/schedulable" style="display:inline">
|
||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||
<input type="hidden" name="schedulable" value="true">
|
||
<button type="submit" class="btn btn-xs btn-outline">Engedélyezés</button>
|
||
</form>
|
||
{{end}}
|
||
{{if and (not .IsDefault) (eq .AppCount 0)}}
|
||
<form method="POST" action="/settings/storage/remove" style="display:inline"
|
||
onsubmit="return confirm('Biztosan eltávolítja a(z) {{.Path}} adattárolót?')">
|
||
<input type="hidden" name="storage_path" value="{{.Path}}">
|
||
<button type="submit" class="btn btn-xs btn-danger-outline">Eltávolítás</button>
|
||
</form>
|
||
{{end}}
|
||
</div>
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
{{else}}
|
||
<div class="empty-state" style="padding:1.5rem">
|
||
Nincs regisztrált adattároló. Adjon hozzá egyet az alábbi űrlappal.
|
||
</div>
|
||
{{end}}
|
||
|
||
<div style="margin-top:1rem;display:flex;gap:.75rem;flex-wrap:wrap">
|
||
<a href="/settings/storage/init" class="btn btn-sm btn-outline">🔧 Új meghajtó inicializálása</a>
|
||
<a href="/settings/storage/attach" class="btn btn-sm btn-outline">🔗 Meglévő meghajtó csatolása</a>
|
||
</div>
|
||
|
||
<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>
|
||
<form method="POST" action="/settings/storage/add" class="storage-add-form">
|
||
<div class="form-group">
|
||
<label for="storage_path">Elérési út</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>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="storage_label">Megnevezés (opcionális)</label>
|
||
<input type="text" id="storage_label" name="storage_label" class="form-control"
|
||
placeholder="Külső 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>
|
||
</label>
|
||
<button type="submit" class="btn btn-primary">Hozzáadás</button>
|
||
</form>
|
||
</details>
|
||
</div>
|
||
|
||
<!-- Section B: Password Change -->
|
||
<div class="settings-card">
|
||
<h3>Jelszó módosítás</h3>
|
||
{{if .AuthEnabled}}
|
||
{{if .PasswordError}}<div class="alert alert-error">{{.PasswordError}}</div>{{end}}
|
||
<form method="POST" action="/settings/password">
|
||
<div class="form-group">
|
||
<label for="current_password">Jelenlegi jelszó</label>
|
||
<input type="password" id="current_password" name="current_password" required
|
||
placeholder="Adja meg a jelenlegi jelszavát" class="form-control">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="new_password">Új jelszó</label>
|
||
<input type="password" id="new_password" name="new_password" required minlength="8"
|
||
placeholder="Legalább 8 karakter" class="form-control">
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="confirm_password">Új jelszó megerősítése</label>
|
||
<input type="password" id="confirm_password" name="confirm_password" required minlength="8"
|
||
placeholder="Jelszó mégegyszer" class="form-control">
|
||
</div>
|
||
<button type="submit" class="btn btn-primary">Jelszó módosítása</button>
|
||
</form>
|
||
{{else}}
|
||
<div class="alert alert-info">
|
||
A jelszavas védelem nincs beállítva. Kérd az üzemeltetőt a beállításhoz.
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
<!-- Section C: Notification Preferences -->
|
||
<div class="settings-card">
|
||
<h3>Értesítések</h3>
|
||
{{if .HubEnabled}}
|
||
{{if .NotificationSuccess}}<div class="alert alert-info">{{.NotificationSuccess}}</div>{{end}}
|
||
{{if .NotificationError}}<div class="alert alert-error">{{.NotificationError}}</div>{{end}}
|
||
<form method="POST" action="/settings/notifications">
|
||
<div class="form-group">
|
||
<label for="notification_email">E-mail cím</label>
|
||
<input type="email" id="notification_email" name="notification_email"
|
||
value="{{with .NotificationPrefs}}{{.Email}}{{end}}"
|
||
placeholder="pelda@email.hu" class="form-control">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Az alábbi eseményekről kapjon értesítést:</label>
|
||
<div class="checkbox-group">
|
||
<label class="toggle">
|
||
<input type="checkbox" name="event_disk_warning" {{with .NotificationPrefs}}{{range .EnabledEvents}}{{if eq . "disk_warning"}}checked{{end}}{{end}}{{end}}>
|
||
<span class="toggle-label">Lemez figyelmeztetés (80%+)</span>
|
||
</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" name="event_backup_failed" {{with .NotificationPrefs}}{{range .EnabledEvents}}{{if eq . "backup_failed"}}checked{{end}}{{end}}{{end}}>
|
||
<span class="toggle-label">Biztonsági mentés sikertelen</span>
|
||
</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" name="event_update_available" {{with .NotificationPrefs}}{{range .EnabledEvents}}{{if eq . "update_available"}}checked{{end}}{{end}}{{end}}>
|
||
<span class="toggle-label">Frissítés elérhető</span>
|
||
</label>
|
||
<label class="toggle">
|
||
<input type="checkbox" name="event_security_update" {{with .NotificationPrefs}}{{range .EnabledEvents}}{{if eq . "security_update"}}checked{{end}}{{end}}{{end}}>
|
||
<span class="toggle-label">Biztonsági frissítés</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<div class="form-group">
|
||
<label for="cooldown_hours">Értesítési szünet</label>
|
||
<div class="form-inline">
|
||
<input type="number" id="cooldown_hours" name="cooldown_hours" min="1" max="168"
|
||
value="{{with .NotificationPrefs}}{{.CooldownHours}}{{end}}"
|
||
class="form-control form-control-narrow">
|
||
<span class="form-hint">óra (azonos probléma esetén ennyi ideig nem küld újat)</span>
|
||
</div>
|
||
</div>
|
||
<div class="form-actions">
|
||
<button type="submit" class="btn btn-primary">Mentés</button>
|
||
<button type="submit" formaction="/settings/notifications/test" class="btn btn-outline">Teszt email küldése</button>
|
||
</div>
|
||
</form>
|
||
{{else}}
|
||
<div class="alert alert-info">
|
||
Az értesítések a központi rendszeren keresztül működnek, ami jelenleg nincs bekapcsolva.
|
||
</div>
|
||
{{end}}
|
||
</div>
|
||
|
||
<script>
|
||
function editStorageLabel(path, currentLabel) {
|
||
var wrap = document.getElementById('label-wrap-' + path);
|
||
if (!wrap) return;
|
||
wrap.innerHTML = '<form method="POST" action="/settings/storage/label" style="display:inline-flex;gap:.5rem;align-items:center">' +
|
||
'<input type="hidden" name="storage_path" value="' + path + '">' +
|
||
'<input type="text" name="storage_label" class="form-control" value="' + currentLabel.replace(/"/g, '"') + '" style="width:200px;padding:.3rem .5rem;font-size:.9rem" maxlength="50">' +
|
||
'<button type="submit" class="btn btn-xs btn-primary">OK</button>' +
|
||
'<button type="button" class="btn btn-xs btn-outline" onclick="cancelEditLabel(\'' + path + '\', \'' + currentLabel.replace(/'/g, "\\'") + '\')">✕</button>' +
|
||
'</form>';
|
||
wrap.querySelector('input[name=storage_label]').focus();
|
||
}
|
||
function cancelEditLabel(path, label) {
|
||
var wrap = document.getElementById('label-wrap-' + path);
|
||
if (!wrap) return;
|
||
// M11: Use DOM manipulation with textContent to prevent XSS if label contains HTML.
|
||
wrap.innerHTML = '';
|
||
var span = document.createElement('span');
|
||
span.className = 'storage-path-label';
|
||
span.id = 'label-display-' + path;
|
||
span.textContent = label;
|
||
var btn = document.createElement('button');
|
||
btn.className = 'btn btn-xs btn-ghost';
|
||
btn.setAttribute('title', 'Átnevezés');
|
||
btn.textContent = '✏️';
|
||
btn.addEventListener('click', function() { editStorageLabel(path, label); });
|
||
wrap.appendChild(span);
|
||
wrap.appendChild(document.createTextNode(' '));
|
||
wrap.appendChild(btn);
|
||
}
|
||
</script>
|
||
{{template "layout_end" .}}
|
||
{{end}}
|