imaging: collapsible tile + ARTS link + reword stage 7

Tile is now <details>. Always-visible summary:
  - QR (96px)
  - serial / hostname / pctype / machine# / status badge
  - friendly stage label + N/M badge + pct
  - progress bar

Click to expand. Body shows:
  - friendly stage hint
  - Intune device id row with [copy] [set category] [ARTS request]
  - metadata one-liner (started / last / MAC / raw current_stage)
  - error banner (if any)
  - LAPS password QR generator
  - log tail
  - Clear button

ARTS button links to https://arts.dw.geaerospace.net/requests/type
for kicking off a new lockdown request (Intune-side step happens
externally; this is a deep-link for convenience).

Stage 7 wording: "Awaiting Intune lockdown" (was "awaiting category /
lockdown" - confusing when category was already assigned). Hint
explicitly mentions category check for cases where it isn't yet set.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-05-15 07:27:35 -04:00
parent a9a7478d5a
commit 65eeead5a0

View File

@@ -49,8 +49,8 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
4: ('Apps installed', 'Type-specific scripts complete. Preparing for Intune enrollment.'), 4: ('Apps installed', 'Type-specific scripts complete. Preparing for Intune enrollment.'),
5: ('Enrolling in Intune', 'PPKG installing - device joining Azure AD + Intune. ~5-10 min, reboot to follow.'), 5: ('Enrolling in Intune', 'PPKG installing - device joining Azure AD + Intune. ~5-10 min, reboot to follow.'),
6: ('Waiting on first Intune sync','Post-PPKG settle (~120s). Triggering Schedule #3 sync repeatedly.'), 6: ('Waiting on first Intune sync','Post-PPKG settle (~120s). Triggering Schedule #3 sync repeatedly.'),
7: ('Registered - awaiting category / lockdown', 7: ('Awaiting Intune lockdown',
'Device ID captured. If category not yet set in Intune, click "set category". Once set, bay waits for the Intune-driven LAPS-prompt reboot to apply lockdown.'), 'Device ID captured. If Device Category is NOT yet set in Intune, click "set category" first. Bay then waits for the Intune-driven LAPS-prompt reboot to apply the lockdown configuration.'),
8: ('Imaging complete', 8: ('Imaging complete',
'Lockdown applied. Bay rebooted into ShopFloor session. Ready for production.') 'Lockdown applied. Bay rebooted into ShopFloor session. Ready for production.')
} %} } %}
@@ -63,9 +63,9 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
{% set is_done = s.status == 'succeeded' %} {% set is_done = s.status == 'succeeded' %}
{% set border = 'danger' if is_failed else ('success' if is_done else 'primary') %} {% set border = 'danger' if is_failed else ('success' if is_done else 'primary') %}
{% set friendly = stage_labels.get(stage_idx, ('Stage ' ~ stage_idx, '')) %} {% set friendly = stage_labels.get(stage_idx, ('Stage ' ~ stage_idx, '')) %}
<div class="card border-{{ border }} mb-2 shadow-sm imaging-card" <details class="card border-{{ border }} mb-2 shadow-sm imaging-card"
data-filter="{{ s.serial|lower }} {{ (s.hostname_target or '')|lower }} {{ (s.pctype or '')|lower }} {{ (s.machinenumber or '')|lower }} {{ (s.intune_device_id or '')|lower }}"> data-filter="{{ s.serial|lower }} {{ (s.hostname_target or '')|lower }} {{ (s.pctype or '')|lower }} {{ (s.machinenumber or '')|lower }} {{ (s.intune_device_id or '')|lower }}">
<div class="card-body py-2"> <summary class="card-body py-2" style="cursor:pointer; list-style:none;">
<div class="d-flex flex-wrap gap-3 align-items-center"> <div class="d-flex flex-wrap gap-3 align-items-center">
{% if s.intune_device_id %} {% if s.intune_device_id %}
<div data-qr="{{ s.intune_device_id }}" data-qr-size="96" data-qr-ec="M" <div data-qr="{{ s.intune_device_id }}" data-qr-size="96" data-qr-ec="M"
@@ -99,7 +99,12 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
role="progressbar" style="width: {{ pct }}%;" role="progressbar" style="width: {{ pct }}%;"
aria-valuenow="{{ pct }}" aria-valuemin="0" aria-valuemax="100"></div> aria-valuenow="{{ pct }}" aria-valuemin="0" aria-valuemax="100"></div>
</div> </div>
{% if friendly[1] %}<div class="small text-muted mt-1">{{ friendly[1] }}</div>{% endif %} </div>
</div>
</summary>
<div class="card-body pt-0 pb-3 border-top">
{% if friendly[1] %}<div class="small text-muted mt-2">{{ friendly[1] }}</div>{% endif %}
{% if s.intune_device_id %} {% if s.intune_device_id %}
<div class="small mt-2" style="font-size:0.75rem;"> <div class="small mt-2" style="font-size:0.75rem;">
@@ -111,6 +116,10 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
style="font-size:0.65rem; line-height:1;" style="font-size:0.65rem; line-height:1;"
target="_blank" rel="noopener" target="_blank" rel="noopener"
href="https://portal.azure.us/?feature.msaljs=false#view/Microsoft_Intune_Devices/DeviceSettingsMenuBlade/~/properties/aadDeviceId/{{ s.intune_device_id }}">set category</a> href="https://portal.azure.us/?feature.msaljs=false#view/Microsoft_Intune_Devices/DeviceSettingsMenuBlade/~/properties/aadDeviceId/{{ s.intune_device_id }}">set category</a>
<a class="btn btn-sm btn-outline-warning py-0 px-1"
style="font-size:0.65rem; line-height:1;"
target="_blank" rel="noopener"
href="https://arts.dw.geaerospace.net/requests/type">ARTS request</a>
</div> </div>
{% endif %} {% endif %}
@@ -120,8 +129,6 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
<span class="me-3">MAC <code>{{ s.mac or '-' }}</code></span> <span class="me-3">MAC <code>{{ s.mac or '-' }}</code></span>
{% if s.current_stage %}<span style="font-family:monospace;">{{ s.current_stage }}</span>{% endif %} {% if s.current_stage %}<span style="font-family:monospace;">{{ s.current_stage }}</span>{% endif %}
</div> </div>
</div>
</div>
{% if s.error %} {% if s.error %}
<div class="alert alert-danger small py-2 mb-2 mt-3"> <div class="alert alert-danger small py-2 mb-2 mt-3">
@@ -130,9 +137,9 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
{% endif %} {% endif %}
{% if s.intune_device_id %} {% if s.intune_device_id %}
<details class="mt-2 laps-card" data-serial="{{ s.serial }}" {% if s.laps_password %}open{% endif %}> <div class="mt-3 laps-card" data-serial="{{ s.serial }}">
<summary class="text-muted small">LAPS password QR (paste -> scan on bay - persists until cleared)</summary> <div class="text-muted small mb-1">LAPS password QR (paste -> scan on bay - persists until cleared)</div>
<div class="d-flex align-items-center gap-2 mt-2"> <div class="d-flex align-items-center gap-2">
<input type="text" <input type="text"
class="form-control form-control-sm laps-input" class="form-control form-control-sm laps-input"
style="font-family: monospace; max-width: 22rem;" style="font-family: monospace; max-width: 22rem;"
@@ -143,11 +150,11 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
<button type="button" class="btn btn-sm btn-outline-secondary laps-clear-btn" {% if not s.laps_password %}style="display:none;"{% endif %}>Clear</button> <button type="button" class="btn btn-sm btn-outline-secondary laps-clear-btn" {% if not s.laps_password %}style="display:none;"{% endif %}>Clear</button>
</div> </div>
<div class="laps-qr-container mt-2"></div> <div class="laps-qr-container mt-2"></div>
</details> </div>
{% endif %} {% endif %}
{% if s.log_tail %} {% if s.log_tail %}
<details> <details class="mt-3">
<summary class="text-muted small">Log tail ({{ s.log_tail | length }} line{{ 's' if s.log_tail | length != 1 }})</summary> <summary class="text-muted small">Log tail ({{ s.log_tail | length }} line{{ 's' if s.log_tail | length != 1 }})</summary>
<pre class="bg-light p-2 mt-2 small mb-0" style="max-height: 12rem; overflow-y: auto;">{% for line in s.log_tail %}{{ line }} <pre class="bg-light p-2 mt-2 small mb-0" style="max-height: 12rem; overflow-y: auto;">{% for line in s.log_tail %}{{ line }}
{% endfor %}</pre> {% endfor %}</pre>
@@ -164,7 +171,7 @@ window.addEventListener('DOMContentLoaded', scheduleImagingReload);
</form> </form>
</div> </div>
</div> </div>
</div> </details>
{% endfor %} {% endfor %}
<div class="card mt-3"> <div class="card mt-3">