Files
deploy-felhom-compose/controller/internal/web/templates/settings.html
T
admin 98834dd7e8 v0.15.0: Attach existing drive wizard (bind mount, no format)
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>
2026-02-18 21:12:02 +01:00

313 lines
16 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{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, '&quot;') + '" 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}}