| 1 |
{% if held_uploads.is_empty() %} |
| 2 |
<div class="text-center dimmed empty-state"> |
| 3 |
No uploads pending review. |
| 4 |
</div> |
| 5 |
{% else %} |
| 6 |
<div class="scroll-x"> |
| 7 |
<table class="compact-table minw-700" aria-label="Held Uploads"> |
| 8 |
<thead> |
| 9 |
<tr> |
| 10 |
<th>Creator</th> |
| 11 |
<th>Item</th> |
| 12 |
<th>Type</th> |
| 13 |
<th>Held</th> |
| 14 |
<th>Layers</th> |
| 15 |
<th>Actions</th> |
| 16 |
</tr> |
| 17 |
</thead> |
| 18 |
<tbody> |
| 19 |
{% for upload in held_uploads %} |
| 20 |
<tr> |
| 21 |
<td> |
| 22 |
{{ upload.creator_username }} |
| 23 |
{% if upload.creator_trusted %} |
| 24 |
<span class="text-xs dimmed">(trusted)</span> |
| 25 |
{% endif %} |
| 26 |
</td> |
| 27 |
<td> |
| 28 |
{{ upload.item_title }} |
| 29 |
{% if let Some(vn) = upload.version_number %} |
| 30 |
<span class="text-xs dimmed">v{{ vn }}</span> |
| 31 |
{% endif %} |
| 32 |
</td> |
| 33 |
<td class="text-sm">{{ upload.upload_type }}</td> |
| 34 |
<td class="text-sm nowrap"> |
| 35 |
{{ upload.held_at }} |
| 36 |
{% if let Some(la) = upload.last_action %} |
| 37 |
<div class="scan-row-meta" title="{{ la.action }} by {{ la.admin_username }} {{ la.when }}"> |
| 38 |
last: {{ la.action }} by {{ la.admin_username }} {{ la.when }} |
| 39 |
</div> |
| 40 |
{% endif %} |
| 41 |
</td> |
| 42 |
<td class="layer-chips-cell"> |
| 43 |
{% if upload.layers.is_empty() %} |
| 44 |
<span class="dimmed text-xs">no scan record</span> |
| 45 |
{% else %} |
| 46 |
<div class="layer-chips"> |
| 47 |
{% for chip in upload.layers %} |
| 48 |
<span class="layer-chip layer-chip-{{ chip.verdict }}" |
| 49 |
title="{{ chip.layer }}: {{ chip.verdict }}{% if let Some(d) = chip.detail %} — {{ d }}{% endif %}"> |
| 50 |
{{ chip.layer }} |
| 51 |
</span> |
| 52 |
{% endfor %} |
| 53 |
</div> |
| 54 |
<details class="layer-detail-disclosure"> |
| 55 |
<summary class="text-xs dimmed">scan detail</summary> |
| 56 |
<dl class="layer-detail-list"> |
| 57 |
{% for chip in upload.layers %} |
| 58 |
<dt><code class="layer-chip layer-chip-{{ chip.verdict }}">{{ chip.layer }}</code> <span class="dimmed">— {{ chip.verdict }}</span></dt> |
| 59 |
<dd>{% if let Some(d) = chip.detail %}{{ d }}{% else %}<span class="dimmed">no detail</span>{% endif %}</dd> |
| 60 |
{% endfor %} |
| 61 |
</dl> |
| 62 |
</details> |
| 63 |
{% endif %} |
| 64 |
</td> |
| 65 |
<td class="nowrap"> |
| 66 |
{% if let Some(vid) = upload.version_id %} |
| 67 |
<button class="btn-primary small" |
| 68 |
hx-post="/api/admin/uploads/versions/{{ vid }}/promote" |
| 69 |
hx-target="#uploads-table" |
| 70 |
hx-swap="innerHTML">Promote</button> |
| 71 |
<button class="btn-secondary small" |
| 72 |
hx-post="/api/admin/uploads/versions/{{ vid }}/rescan" |
| 73 |
hx-target="#uploads-table" |
| 74 |
hx-swap="innerHTML" |
| 75 |
title="Re-run pipeline (use after a layer fix)">Re-scan</button> |
| 76 |
<button class="btn-danger small" |
| 77 |
hx-post="/api/admin/uploads/versions/{{ vid }}/quarantine" |
| 78 |
hx-target="#uploads-table" |
| 79 |
hx-swap="innerHTML" |
| 80 |
hx-confirm="Quarantine this upload? Quarantine is sticky — the file stays in DB for audit but is unavailable to fans.">Quarantine</button> |
| 81 |
{% else %} |
| 82 |
<button class="btn-primary small" |
| 83 |
hx-post="/api/admin/uploads/items/{{ upload.item_id }}/promote" |
| 84 |
hx-target="#uploads-table" |
| 85 |
hx-swap="innerHTML">Promote</button> |
| 86 |
<button class="btn-secondary small" |
| 87 |
hx-post="/api/admin/uploads/items/{{ upload.item_id }}/rescan" |
| 88 |
hx-target="#uploads-table" |
| 89 |
hx-swap="innerHTML" |
| 90 |
title="Re-run pipeline (use after a layer fix)">Re-scan</button> |
| 91 |
<button class="btn-danger small" |
| 92 |
hx-post="/api/admin/uploads/items/{{ upload.item_id }}/quarantine" |
| 93 |
hx-target="#uploads-table" |
| 94 |
hx-swap="innerHTML" |
| 95 |
hx-confirm="Quarantine this upload?">Quarantine</button> |
| 96 |
{% endif %} |
| 97 |
{% if !upload.creator_trusted %} |
| 98 |
<button class="btn-secondary small" |
| 99 |
hx-post="/api/admin/users/{{ upload.creator_id }}/trust" |
| 100 |
hx-target="#uploads-table" |
| 101 |
hx-swap="innerHTML">Trust Creator</button> |
| 102 |
{% endif %} |
| 103 |
</td> |
| 104 |
</tr> |
| 105 |
{% endfor %} |
| 106 |
</tbody> |
| 107 |
</table> |
| 108 |
</div> |
| 109 |
{% endif %} |
| 110 |
|