Initialer Import des AssetManagers

This commit is contained in:
2026-08-02 21:28:50 +00:00
commit ed72ce8821
256 changed files with 26361 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
{% extends 'base.html' %}
{% block content %}
<div class="backup-page">
<div class="backup-page-header">
<div>
<h1>{{ t('backup.title', 'Backups') }}</h1>
<p class="muted">{{ t('backup.description', 'Create, download, upload and restore complete AssetManager backups.') }}</p>
</div>
<form method="post" action="/settings/backup/create" class="backup-create-form">
<button type="submit" class="button backup-primary-action">{{ t('backup.create_now', 'Create backup now') }}</button>
</form>
</div>
<div class="backup-summary-grid">
<section class="backup-summary-card">
<span class="backup-summary-icon" aria-hidden="true">📁</span>
<div><span class="backup-summary-label">{{ t('backup.directory', 'Backup directory') }}</span><strong><code>{{ backup_directory }}</code></strong></div>
</section>
<section class="backup-summary-card">
<span class="backup-summary-icon" aria-hidden="true">🕒</span>
<div><span class="backup-summary-label">{{ t('backup.interval', 'Interval') }}</span><strong>{{ t('backup.every_hours', 'Every {hours} hours', hours=backup_interval_hours) }}</strong></div>
</section>
<section class="backup-summary-card">
<span class="backup-summary-icon" aria-hidden="true">🗓️</span>
<div><span class="backup-summary-label">{{ t('backup.retention', 'Retention') }}</span><strong>{{ t('backup.days', '{days} days', days=backup_retention_days) }}</strong></div>
</section>
</div>
<section class="panel backup-panel">
<div class="backup-panel-heading">
<div><h2>{{ t('backup.automatic_title', 'Automatic backup') }}</h2><p class="muted">{{ t('backup.automatic_help', 'Backups are created automatically according to the configured interval and deleted after the retention period.') }}</p></div>
<span class="backup-status-badge">{{ t('backup.active', 'Active') }}</span>
</div>
<div class="backup-content-note"><span aria-hidden="true"></span><p>{{ t('backup.contents_help', 'Each backup contains a PostgreSQL database dump, configuration, APPINFO and uploaded files. Environment variables and the .env file are not included.') }}</p></div>
</section>
<section class="panel backup-panel">
<div class="backup-panel-heading"><div><h2>{{ t('backup.upload_title', 'Upload backup') }}</h2><p class="muted">{{ t('backup.upload_help', 'Upload an AssetManager backup ZIP to make it available for download or restoration.') }}</p></div></div>
<form method="post" action="/settings/backup/upload" enctype="multipart/form-data" class="backup-upload-form">
<input type="file" name="backup_file" accept=".zip,application/zip" required>
<button type="submit" class="button-secondary">{{ t('backup.upload', 'Upload') }}</button>
</form>
</section>
<section class="panel backup-panel">
<div class="backup-panel-heading"><div><h2>{{ t('backup.available', 'Available backups') }}</h2><p class="muted">{{ t('backup.available_help', 'Stored backups can be downloaded, restored or deleted here.') }}</p></div><span class="backup-count">{{ backups|length }}</span></div>
{% if backups %}
<div class="table-scroll backup-table-wrap"><table class="data-table backup-table"><thead><tr>
<th>{{ t('backup.file', 'File') }}</th><th>{{ t('backup.created', 'Created') }}</th><th>{{ t('backup.version', 'Version') }}</th><th>{{ t('backup.reason', 'Reason') }}</th><th>{{ t('backup.size', 'Size') }}</th><th>{{ t('common.actions', 'Actions') }}</th>
</tr></thead><tbody>{% for backup in backups %}<tr>
<td><code>{{ backup.name }}</code>{% if not backup.valid %}<br><span class="muted">{{ t('backup.invalid_metadata', 'Metadata could not be read') }}</span>{% endif %}</td>
<td><time class="local-time" datetime="{{ backup.modified_at.isoformat() }}" data-utc="{{ backup.modified_at.isoformat() }}">{{ backup.modified_at.strftime('%Y-%m-%d %H:%M:%S') }}</time></td><td>{{ backup.version if backup.version else t('backup.version_unknown') }}</td><td>{{ t('backup.reason_' ~ (backup.reason or 'unknown'), backup.reason or '—') }}</td><td>{{ '%.2f'|format(backup.size / 1024 / 1024) }} MB</td>
<td><div class="backup-actions"><a class="button button-secondary" href="/settings/backup/{{ backup.name }}/download">{{ t('backup.download', 'Download') }}</a><button type="button" class="button-secondary" onclick="document.getElementById('restore-{{ loop.index }}').showModal()">{{ t('backup.restore', 'Restore') }}</button><form method="post" action="/settings/backup/{{ backup.name }}/delete" onsubmit="return confirm('{{ t('backup.delete_confirm', 'Delete this backup permanently?')|e }}')"><button type="submit" class="button-danger">{{ t('common.delete', 'Delete') }}</button></form></div>
<dialog id="restore-{{ loop.index }}" class="backup-dialog"><form method="post" action="/settings/backup/{{ backup.name }}/restore"><h2>{{ t('backup.restore_title', 'Restore backup') }}</h2><p>{{ t('backup.restore_warning', 'The current database, configuration and uploads will be replaced. A safety backup is created immediately before restoration.') }}</p><label>{{ t('backup.restore_confirmation', 'Enter RESTORE to confirm') }}<input name="confirmation" autocomplete="off" required></label><div class="form-actions"><button type="button" class="button-secondary" onclick="this.closest('dialog').close()">{{ t('common.cancel', 'Cancel') }}</button><button type="submit" class="button-danger">{{ t('backup.restore_now', 'Restore now') }}</button></div></form></dialog></td>
</tr>{% endfor %}</tbody></table></div>
{% else %}<div class="backup-empty-state"><span aria-hidden="true">🗄️</span><strong>{{ t('backup.none_title', 'No backups yet') }}</strong><p class="muted">{{ t('backup.none', 'No backups are available yet.') }}</p></div>{% endif %}
</section>
</div>
{% endblock %}