webapp: Blancco variant of the /imaging tiles

Sessions with source/pctype "blancco" (posted by blancco-init.sh and
blancco-progress.py) now render with their own stage labels
(Downloading, Starting, Licensing, Erasing, Erasure finished, Report
sent, Wipe complete; Erasure FAILED on failure), a WIPE badge with the
drive percentage instead of "no DeviceId", the current step beside the
stage, and an Erasure reports link. The drive percentage is folded into
the bar across stage 4. The LAPS QR card is hidden for Blancco tiles.

Also render the bar percentage as an integer: round() returns a float,
so every tile showed e.g. "57.0%".
This commit is contained in:
cproudlock
2026-10-05 12:52:08 -04:00
parent 19049e6b1f
commit eff956ae6c

View File

@@ -13,6 +13,18 @@
'Lockdown applied. Bay rebooted into ShopFloor session. Ready for production.') 'Lockdown applied. Bay rebooted into ShopFloor session. Ready for production.')
} %} } %}
{# Blancco Drive Eraser sessions (source/pctype "blancco"), posted by
blancco-init.sh and blancco-progress.py; stage_total 7. #}
{% set blancco_stage_labels = {
1: ('Downloading Blancco', 'PXE boot: loading the Blancco image into RAM.'),
2: ('Starting Blancco', 'Blancco is starting up.'),
3: ('Licensing', 'Waiting for the Blancco cloud licence (WiFi INTERNETACCESS).'),
4: ('Erasing', 'Drive erasure in progress. Do not power off.'),
5: ('Erasure finished', 'Report saved on the PC.'),
6: ('Report sent', 'Report uploaded to the Blancco cloud; a copy goes to the share.'),
7: ('Wipe complete', 'Erasure succeeded. Report is on the Blancco reports share.')
} %}
{% set inferred_stage_labels = { {% set inferred_stage_labels = {
'stage_0_dhcp': ('DHCP lease issued', 'Client got a DHCP lease but has not fetched the bootloader yet.'), 'stage_0_dhcp': ('DHCP lease issued', 'Client got a DHCP lease but has not fetched the bootloader yet.'),
'stage_0_tftp_bios': ('TFTP bootloader (BIOS)','Client fetched undionly.kpxe via TFTP. Booting iPXE.'), 'stage_0_tftp_bios': ('TFTP bootloader (BIOS)','Client fetched undionly.kpxe via TFTP. Booting iPXE.'),
@@ -25,9 +37,20 @@
{% for s in sessions %} {% for s in sessions %}
{% set is_inferred = (s.source == 'inferred') %} {% set is_inferred = (s.source == 'inferred') %}
{% set is_blancco = (s.source == 'blancco' or s.pctype == 'blancco') %}
{% set stage_idx = s.stage_index | int(0) %} {% set stage_idx = s.stage_index | int(0) %}
{% set stage_total = s.stage_total | int(0) %} {% set stage_total = s.stage_total | int(0) %}
{% set pct = 100 if s.status == 'succeeded' else ((stage_idx / stage_total * 100) | round(0, 'floor')) if stage_total > 0 else 0 %} {% set pct = 100 if s.status == 'succeeded' else ((stage_idx / stage_total * 100) | round(0, 'floor')) if stage_total > 0 else 0 %}
{# Blancco erasing: fold the drive % ("... [75%]") into the bar between
the start of stage 4 and the start of stage 5. #}
{% set drive_pct = None %}
{% if is_blancco and stage_idx == 4 and s.current_stage and '%]' in s.current_stage %}
{% set drive_pct = s.current_stage.split('[')[-1].split('%')[0] | int(0) %}
{% if stage_total > 0 and s.status != 'succeeded' %}
{% set pct = (((stage_idx - 1) + drive_pct / 100) / stage_total * 100) | round(0, 'floor') %}
{% endif %}
{% endif %}
{% set pct = pct | int %}
{% set is_failed = s.status == 'failed' %} {% set is_failed = s.status == 'failed' %}
{% set is_done = s.status == 'succeeded' %} {% set is_done = s.status == 'succeeded' %}
{% if is_inferred %} {% if is_inferred %}
@@ -37,6 +60,12 @@
{% endif %} {% endif %}
{% if is_inferred %} {% if is_inferred %}
{% set friendly = inferred_stage_labels.get(s.current_stage, ('Inferred from logs', s.current_stage or '')) %} {% set friendly = inferred_stage_labels.get(s.current_stage, ('Inferred from logs', s.current_stage or '')) %}
{% elif is_blancco %}
{% if s.status == 'failed' %}
{% set friendly = ('Erasure FAILED', 'Blancco reported a failed erasure step. Check the log tail and the report.') %}
{% else %}
{% set friendly = blancco_stage_labels.get(stage_idx, ('Stage ' ~ stage_idx, '')) %}
{% endif %}
{% else %} {% else %}
{% set friendly = stage_labels.get(stage_idx, ('Stage ' ~ stage_idx, '')) %} {% set friendly = stage_labels.get(stage_idx, ('Stage ' ~ stage_idx, '')) %}
{% if stage_idx == 1 and s.current_stage and 'bios' in s.current_stage|lower %} {% if stage_idx == 1 and s.current_stage and 'bios' in s.current_stage|lower %}
@@ -75,7 +104,7 @@
{% else %} {% else %}
<div class="d-flex align-items-center justify-content-center eyebrow" <div class="d-flex align-items-center justify-content-center eyebrow"
style="width:96px; height:96px; border-radius:0.25rem; flex-shrink:0; text-align:center; padding:0.25rem; background:var(--bg); border:1px solid var(--border);"> style="width:96px; height:96px; border-radius:0.25rem; flex-shrink:0; text-align:center; padding:0.25rem; background:var(--bg); border:1px solid var(--border);">
{% if is_inferred %}log-only{% else %}no DeviceId{% endif %} {% if is_inferred %}log-only{% elif is_blancco %}WIPE{% if drive_pct is not none %}<br>{{ drive_pct }}%{% endif %}{% else %}no DeviceId{% endif %}
</div> </div>
{% endif %} {% endif %}
@@ -98,6 +127,7 @@
<div class="d-flex justify-content-between align-items-baseline mt-2"> <div class="d-flex justify-content-between align-items-baseline mt-2">
<div class="d-flex align-items-center gap-2"> <div class="d-flex align-items-center gap-2">
<strong>{{ friendly[0] }}</strong> <strong>{{ friendly[0] }}</strong>
{% if is_blancco and stage_idx == 4 and s.current_stage %}<span class="mono" style="color:var(--text-light); font-size:0.8rem;">{{ s.current_stage | replace('Erasing: ', '') }}</span>{% endif %}
{% if not is_inferred %} {% if not is_inferred %}
<span class="badge badge-secondary">{{ stage_idx }}/{{ stage_total or '?' }}</span> <span class="badge badge-secondary">{{ stage_idx }}/{{ stage_total or '?' }}</span>
{% endif %} {% endif %}
@@ -146,7 +176,13 @@
</div> </div>
{% endif %} {% endif %}
{% if not is_inferred %} {% if is_blancco %}
<div class="mt-3">
<a href="{{ url_for('blancco_reports') }}" class="btn btn-sm btn-outline-primary btn-row-action">Erasure reports</a>
</div>
{% endif %}
{% if not is_inferred and not is_blancco %}
<div class="mt-3 laps-card" data-serial="{{ s.serial }}"> <div class="mt-3 laps-card" data-serial="{{ s.serial }}">
<div class="eyebrow mb-2">LAPS password QR (paste -> scan on bay - persists until cleared)</div> <div class="eyebrow mb-2">LAPS password QR (paste -> scan on bay - persists until cleared)</div>
<div class="d-flex flex-wrap align-items-center gap-2"> <div class="d-flex flex-wrap align-items-center gap-2">