mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-01-20 19:39:59 -06:00
feat(core/auth/ui): proxy-aware config, optional OIDC, i18n v4, health checks
- core: add ProxyFix, robust logging setup, rate-limit defaults; mask DB URL in logs
- db: prefer Postgres when POSTGRES_* envs present; initialization helpers and safe task table migration check
- i18n: upgrade to Flask-Babel v4 with locale selector; compile catalogs; add set-language route
- auth: optional OIDC via Authlib (login, callback, logout); login rate limiting; profile language and theme persistence; ensure admin promotion
- admin: branding logo upload/serve; PDF layout editor with preview/reset; backup/restore with progress; system info; license-server controls
- ui: new base layout with improved nav, mobile tab bar, theme/density toggles, CSRF meta + auto-injection, DataTables/Chart.js, Socket.IO boot
- ops: add /_health and /_ready endpoints; Docker healthcheck targets /_health; enable top-level templates via ChoiceLoader
- deps: update/add Authlib, Flask-Babel 4, and related security/util packages
Refs: app/__init__.py, app/config.py, app/routes/{auth,admin,main}.py, app/templates/base.html, Dockerfile, requirements.txt, templates/*
107 lines
5.2 KiB
HTML
107 lines
5.2 KiB
HTML
{% extends 'base.html' %}
|
|
|
|
{% block title %}{{ _('Restore Backup') }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="container-fluid">
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div class="d-flex align-items-center">
|
|
<h1 class="h3 mb-0 me-3">
|
|
<i class="fas fa-undo-alt text-danger"></i>
|
|
{{ _('Restore Backup') }}
|
|
</h1>
|
|
<span class="badge bg-danger fs-6">{{ _('Danger Operation') }}</span>
|
|
</div>
|
|
<a href="{{ url_for('admin.admin_dashboard') }}" class="btn btn-outline-secondary">
|
|
<i class="fas fa-arrow-left"></i> {{ _('Back to Dashboard') }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<div class="card shadow-sm border-0">
|
|
<div class="card-header bg-white py-3">
|
|
<h6 class="m-0 font-weight-bold text-primary">
|
|
<i class="fas fa-file-archive me-2"></i>{{ _('Upload Backup Archive (.zip)') }}
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="alert alert-warning">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
{{ _('Restoring a backup will overwrite your current database and files. Ensure you have a recent backup before proceeding.') }}
|
|
</div>
|
|
{% if progress %}
|
|
<div class="mb-3">
|
|
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
<strong>{{ _('Status:') }}</strong>
|
|
<span class="badge {{ 'bg-success' if progress.status == 'done' else ('bg-danger' if progress.status == 'error' else 'bg-info') }}">
|
|
{{ progress.status|title }}
|
|
</span>
|
|
</div>
|
|
<div class="progress progress-thin mb-2">
|
|
<div class="progress-bar" role="progressbar" style="width: {{ progress.percent }}%">
|
|
{{ progress.percent }}%
|
|
</div>
|
|
</div>
|
|
<div class="text-muted small">{{ progress.message }}</div>
|
|
</div>
|
|
<script>
|
|
// Auto-refresh progress every 2s while running
|
|
(function(){
|
|
const status = "{{ progress.status }}";
|
|
if (status === 'running') {
|
|
setTimeout(function(){ window.location.href = "{{ url_for('admin.restore', token=token) }}"; }, 2000);
|
|
}
|
|
})();
|
|
</script>
|
|
{% endif %}
|
|
<form action="{{ url_for('admin.restore') }}" method="post" enctype="multipart/form-data">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
<div class="mb-3">
|
|
<label for="backup_file" class="form-label">{{ _('Backup Archive (.zip)') }}</label>
|
|
<input class="form-control" type="file" id="backup_file" name="backup_file" accept=".zip" required>
|
|
<div class="form-text">
|
|
<i class="fas fa-info-circle me-1"></i>
|
|
{{ _('Select a .zip archive previously created via the Backup action.') }}
|
|
</div>
|
|
</div>
|
|
<div class="d-flex gap-2">
|
|
<button type="submit" class="btn btn-danger">
|
|
<i class="fas fa-undo-alt me-1"></i> {{ _('Restore') }}
|
|
</button>
|
|
<a href="{{ url_for('admin.admin_dashboard') }}" class="btn btn-outline-secondary">
|
|
{{ _('Cancel') }}
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-4">
|
|
<div class="card shadow-sm border-0">
|
|
<div class="card-header bg-white py-3">
|
|
<h6 class="m-0 font-weight-bold text-primary">
|
|
<i class="fas fa-shield-alt me-2"></i>{{ _('Safety Tips') }}
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="text-muted mb-0">
|
|
<li>{{ _('Verify the backup archive integrity before restoring.') }}</li>
|
|
<li>{{ _('Ensure no active writes are occurring during restore.') }}</li>
|
|
<li>{{ _('Keep a copy of the current data in case you need to roll back.') }}</li>
|
|
<li>{{ _('After restore, review settings and re-run migrations if required.') }}</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
|