Pagination (200/page), batched+checkpointed ingest (batch_size, resume-safe), quality max_files slicing, upload page; Caddy routes for prefect/photo-filter

This commit is contained in:
2026-08-08 13:36:00 +10:00
parent 1814b5c5c4
commit 0d20c29f35
7 changed files with 309 additions and 74 deletions

View File

@@ -41,6 +41,9 @@
.none { color: #666; font-style: italic; padding: 2rem; text-align: center; }
.selall { display: inline-flex; align-items: center; gap: .35rem; background: #222; border: 1px solid #444; border-radius: 6px; padding: .4rem .8rem; cursor: pointer; }
.toast { position: fixed; bottom: 1.2rem; right: 1.2rem; background: #1d4; color: #031; padding: .7rem 1rem; border-radius: 8px; display: none; z-index: 50; font-size: .9rem; box-shadow: 0 2px 12px rgba(0,0,0,.5); }
.pager { display: flex; gap: 1rem; align-items: center; justify-content: center; padding: 1.5rem; }
.pager a { color: #6cf; text-decoration: none; padding: .4rem .8rem; background: #222; border: 1px solid #444; border-radius: 6px; }
.pager span { color: #999; }
</style>
</head>
<body>
@@ -72,7 +75,7 @@
<button class="btn-reset" id="bulk-reset">↺ Reset</button>
</div>
<div class="toast" id="toast"></div>
<p class="count">{{ items|length }} images</p>
<p class="count">{{ total }} images · page {{ page }}/{{ pages }}</p>
<main>
<div class="grid" id="review-grid">
{% for item in items %}
@@ -81,6 +84,17 @@
<p class="none">No images match the filter.</p>
{% endfor %}
</div>
{% if pages > 1 %}
<div class="pager">
{% if page > 1 %}
<a href="/review?page={{ page-1 }}{% if source %}&source={{ source }}{% endif %}{% if status %}&status={{ status }}{% endif %}">← Prev</a>
{% endif %}
<span>page {{ page }} / {{ pages }}</span>
{% if page < pages %}
<a href="/review?page={{ page+1 }}{% if source %}&source={{ source }}{% endif %}{% if status %}&status={{ status }}{% endif %}">Next →</a>
{% endif %}
</div>
{% endif %}
</main>
<script>
// Selection is DERIVED from DOM checkboxes — single source of truth.
@@ -158,7 +172,11 @@
function updateCount() {
const el = document.querySelector('.count');
const n = document.querySelectorAll('.card').length;
if (el) el.textContent = n + ' images';
if (el && el.textContent.includes('images')) {
// preserve the "· page X/Y" part, update the leading card count
const m = el.textContent.match(/page (\d+)\/(\d+)/);
el.textContent = n + ' images' + (m ? ' · page ' + m[1] + '/' + m[2] : '');
}
}
function showToast(msg, isErr) {