Webapp: evidence pack date range, US month labels, hardware gap rows

Evidence pack takes ?from=&to= (inclusive, Eastern time) with From/To
pickers and quick ranges; ZIP is named ENT-056_<site>_<from>_to_<to>.
Month keys show as 'September 2026'. Hardware gap rows on the to-do
use the shared one-line grid with chips for the missing pack or BIOS.
This commit is contained in:
cproudlock
2026-10-14 15:08:36 -04:00
parent a54df7ebd9
commit 2dbaaded44
4 changed files with 116 additions and 15 deletions

View File

@@ -63,9 +63,19 @@
</details>
<details class="more">
<summary class="ui-btn">Evidence pack</summary>
<form class="menu" method="get" action="{{ url_for('blancco_evidence_pack') }}" style="width: min(320px, calc(100vw - 32px)); padding: 14px; gap: 10px">
<label for="evidenceMonth" class="sub">ENT-056/158 evidence pack for</label>
<input id="evidenceMonth" type="month" name="month" value="{{ last_month }}" class="field" required>
<form class="menu" method="get" action="{{ url_for('blancco_evidence_pack') }}" style="width: min(380px, calc(100vw - 32px)); padding: 14px; gap: 10px">
<div class="sub" style="white-space: normal">ENT-056/158 evidence pack: every report erased between these dates (Eastern time, both days included).</div>
<div style="display: flex; gap: 8px; flex-wrap: wrap">
<label class="sub" style="display: flex; flex-direction: column; gap: 4px">From
<input id="evidenceFrom" type="date" name="from" value="{{ pack_from }}" class="field" required></label>
<label class="sub" style="display: flex; flex-direction: column; gap: 4px">To
<input id="evidenceTo" type="date" name="to" value="{{ pack_to }}" class="field" required></label>
</div>
<div style="display: flex; gap: 6px; flex-wrap: wrap" aria-label="Quick ranges">
<button type="button" class="fbtn" data-range="last-month">Last month</button>
<button type="button" class="fbtn" data-range="this-month">This month</button>
<button type="button" class="fbtn" data-range="last-30">Last 30 days</button>
</div>
<button type="submit" class="ui-btn pri">Download</button>
<div class="sub" style="white-space: normal">Built automatically into <span class="mono">evidence\</span> on the reports share on the 1st.</div>
</form>
@@ -191,6 +201,19 @@
document.getElementById('deleteFilename').textContent = filename;
document.getElementById('deleteForm').action = "{{ url_for('blancco_delete_report', filename='__F__') }}".replace('__F__', encodeURIComponent(filename));
});
// Evidence pack quick ranges (dates in the browser's local day; the
// server reads them as Eastern-time days).
function iso(d) { return d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2); }
document.querySelectorAll('[data-range]').forEach(function (b) {
b.addEventListener('click', function () {
var now = new Date(), from, to;
if (b.dataset.range === 'last-month') { from = new Date(now.getFullYear(), now.getMonth() - 1, 1); to = new Date(now.getFullYear(), now.getMonth(), 0); }
else if (b.dataset.range === 'this-month') { from = new Date(now.getFullYear(), now.getMonth(), 1); to = now; }
else { to = now; from = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 29); }
document.getElementById('evidenceFrom').value = iso(from);
document.getElementById('evidenceTo').value = iso(to);
});
});
// Search and filters: rows hide; a month with no visible row hides; a
// search or filter opens the months so matches are seen.
var q = document.getElementById('rq'), f = '';

View File

@@ -22,7 +22,8 @@
.tgrid { display: grid; grid-template-columns: 96px 104px minmax(0, 1fr) 200px 14px; align-items: center; gap: 0 14px;
padding: 11px 210px 11px 24px; font-size: 14px; min-height: 24px; }
.tgrid.nochev { grid-template-columns: 96px 104px minmax(0, 1fr) 200px; }
.tgrid.hw { grid-template-columns: minmax(0, 1fr) minmax(0, 260px) 110px 14px; }
.tgrid.hw { grid-template-columns: 96px minmax(0, 1fr) auto 14px; }
.hw-miss { display: flex; gap: 6px; flex-wrap: nowrap; justify-content: flex-end; min-width: 0; }
.twhen { font-size: 13px; color: var(--muted); white-space: nowrap; }
.ui-row.done { background: var(--surface-2); }
.ui-row.done .tgrid { color: var(--muted); }
@@ -152,14 +153,14 @@
{# ---- 3. Evidence packs ---- #}
<div class="sect" id="ev"><h2>Evidence packs to upload</h2><span class="sub">Built on the 1st of each month. Upload to the site's ENT-056 / ENT-158 folders in Box, then mark.</span></div>
{% for p in todo.evidence %}
<div class="ui-row"><div class="tgrid nochev"><span class="twhen mono">{{ p.month }}</span><span class="mono trunc" style="grid-column: span 2">{{ p.file }}</span><span></span></div>
<div class="ui-row"><div class="tgrid nochev"><span class="twhen">{{ p.month | month_label }}</span><span class="mono trunc" style="grid-column: span 2">{{ p.file }}</span><span></span></div>
<div class="act"><a class="ui-btn" href="{{ url_for('blancco_evidence_file', filename=p.file) }}">Download</a>
{{ attest('evidence_uploaded', p.month, 'Mark uploaded', 'Record that ' ~ p.file ~ ' is uploaded to Box? This is logged in the audit log.') }}</div></div>
{% else %}
<div class="empty">No pack waiting. The next one is built on the 1st.</div>
{% endfor %}
{% for r in recent.evidence_uploaded %}
<div class="ui-row done"><div class="tgrid nochev"><span class="twhen mono">{{ r.key }}</span><span style="grid-column: span 2">Evidence pack</span><span class="sub">Uploaded {{ r.ts | local_dt }}</span></div>
<div class="ui-row done"><div class="tgrid nochev"><span class="twhen">{{ r.key | month_label }}</span><span style="grid-column: span 2">Evidence pack</span><span class="sub">Uploaded {{ r.ts | local_dt }}</span></div>
<div class="act">{{ undo_form('evidence_uploaded', r.key, 'evidence pack ' ~ r.key ~ ' uploaded') }}</div></div>
{% endfor %}
@@ -186,9 +187,12 @@
<div class="ui-row">
<details>
<summary class="tgrid hw">
<span class="trunc mono c-model">{{ r.model }}</span>
<span class="sub trunc">{{ what | join('; ') }}</span>
<span class="twhen">seen {{ r.last_seen | local_dt }}</span>
<span class="twhen mono" title="Last seen {{ r.last_seen | local_dt }}">{{ r.last_seen | short_date }}</span>
<span class="trunc c-model">{{ r.model }}</span>
<span class="hw-miss">
{% if r.missing %}{{ ui.chip('No driver pack' if r.missing | length > 1 else 'No pack: ' ~ (r.missing[0] | replace('gea-', '')), 'err') }}{% endif %}
{% if r.bios.status == 'none' %}{{ ui.chip('No BIOS entry', 'warn') }}{% elif r.bios.status == 'file-missing' %}{{ ui.chip('BIOS file missing', 'err') }}{% endif %}
</span>
<span class="chev" aria-hidden="true">&#9662;</span>
</summary>
<div class="tbody"><dl class="kv">