Initial commit
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
{% extends "base.html" %}
|
||||
{% block title %}Dashboard — CalibreSync{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<h1>Dashboard</h1>
|
||||
<div class="header-actions">
|
||||
{% if interval > 0 %}
|
||||
<span class="schedule-badge">
|
||||
Auto every {{ interval }}m
|
||||
{% if next_run %} — next: {{ next_run }}{% endif %}
|
||||
</span>
|
||||
{% endif %}
|
||||
<form method="post" action="/sync" style="display:inline">
|
||||
{% if sync_running %}
|
||||
<button class="btn btn-disabled" disabled>Sync running…</button>
|
||||
{% else %}
|
||||
<button class="btn btn-primary">Run Sync Now</button>
|
||||
{% endif %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if request.query_params.get("started") %}
|
||||
<div class="alert alert-success">Sync started in background.</div>
|
||||
{% endif %}
|
||||
{% if request.query_params.get("already_running") %}
|
||||
<div class="alert alert-warning">A sync is already running.</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.total_zips }}</div>
|
||||
<div class="stat-label">Zip archives processed</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.uploaded }}</div>
|
||||
<div class="stat-label">Books uploaded</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.skipped }}</div>
|
||||
<div class="stat-label">Duplicates skipped</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-value">{{ stats.total_books }}</div>
|
||||
<div class="stat-label">Total book records</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Recent sync runs</h2>
|
||||
{% if runs %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Started</th>
|
||||
<th>Finished</th>
|
||||
<th>Status</th>
|
||||
<th>New zips</th>
|
||||
<th>Uploaded</th>
|
||||
<th>Skipped</th>
|
||||
<th>Errors</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for r in runs %}
|
||||
<tr>
|
||||
<td>{{ r.started_at[:19].replace("T"," ") }}</td>
|
||||
<td>{{ r.finished_at[:19].replace("T"," ") if r.finished_at else "—" }}</td>
|
||||
<td><span class="badge badge-{{ r.status }}">{{ r.status }}</span></td>
|
||||
<td>{{ r.zips_new }}</td>
|
||||
<td>{{ r.books_uploaded }}</td>
|
||||
<td>{{ r.books_skipped }}</td>
|
||||
<td>{{ r.books_errored }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p class="muted">No sync runs yet. Click "Run Sync" to start.</p>
|
||||
{% endif %}
|
||||
|
||||
<h2>Recent zip archives</h2>
|
||||
{% if zips %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Remote path</th>
|
||||
<th>Size</th>
|
||||
<th>Processed</th>
|
||||
<th>Status</th>
|
||||
<th>Error</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for z in zips %}
|
||||
<tr>
|
||||
<td class="mono">{{ z.remote_path }}</td>
|
||||
<td>{{ (z.file_size / 1048576) | round(1) }} MB</td>
|
||||
<td>{{ z.processed_at[:19].replace("T"," ") if z.processed_at else "—" }}</td>
|
||||
<td><span class="badge badge-{{ z.status }}">{{ z.status }}</span></td>
|
||||
<td class="muted small">{{ z.error_msg or "" }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p class="muted">No zip archives processed yet.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if sync_running %}
|
||||
<script>
|
||||
setTimeout(() => location.reload(), 5000);
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user