Files
pxe-server/webapp/templates/hardware.html
cproudlock 397063f987 Webapp: Updates pages, image page tabs with review-before-save, BPRT sync
Updates group:
- Dell drivers and BIOS: check Dell's catalogs against all three driver maps
  and models.txt, download with a shared speed cap, repack, preview, apply
  with backups and rollback.
- iPXE boot files: check GitHub for the signed Secure Boot set, verify the
  sha256 and each file's signer, install atomically, roll back. Includes the
  by-hand procedure.
- Blancco: upload a release, stage it, test-boot it from the menu, activate,
  roll back.
- BPRT sync: validate a batch uploaded from the MediaCreator Lite cache
  (scripts/windows/Sync-BPRT.ps1 or a zip), show the diff, swap with the site
  overlay files kept.

Images: one sidebar entry per image with Overview, Drivers, Unattend and OS and
Packages tabs. Every save shows a diff first, keeps the file's format, makes a
backup and can be undone. Driver lint runs inline.

Enrollment: upload standard/engineer MCL packages, one per tenant/purpose,
with archive and restore. Hardware coverage counts engineer as Win11.
2026-10-13 16:58:55 -04:00

89 lines
4.4 KiB
HTML

{% extends "base.html" %}
{% block title %}Hardware Coverage - PXE Server Manager{% endblock %}
{% macro driver_badge(d) -%}
{% if d.status == 'ok' %}<span class="badge badge-success" title="{{ d.file }}">OK</span>
{% elif d.status == 'no-entry' %}<span class="badge badge-danger" title="No HardwareDriver.json entry matches this model">Missing</span>
{% elif d.status == 'zip-missing' %}<span class="badge badge-danger" title="Entry {{ d.file }} matches, but the zip is not on the server">Zip missing</span>
{% else %}<span class="text-muted">-</span>{% endif %}
{%- endmacro %}
{% macro bios_badge(b) -%}
{% if b.status == 'current' %}<span class="badge badge-success">{{ b.target }} (current)</span>
{% elif b.status == 'update' %}<span class="badge badge-info" title="{{ b.file }}">Flashes to {{ b.target }}</span>
{% elif b.status == 'file-missing' %}<span class="badge badge-danger" title="{{ b.file }} not in the BIOS folder">File missing</span>
{% else %}<span class="badge badge-danger">No BIOS entry</span>{% endif %}
{%- endmacro %}
{# A newer Dell pack/BIOS for the file this model uses, from the last Updates > Dell scan. #}
{% macro update_hint(found, file) -%}
{% if file and file | lower in found %}
<div class="mt-1"><a href="{{ url_for('dell_updates.page') }}" class="badge badge-info text-decoration-none" title="{{ file }}: Dell has {{ found[file | lower] or 'a newer version' }}. Open Updates to download it.">Update {{ found[file | lower] }}</a></div>
{% endif %}
{%- endmacro %}
{% block content %}
<div class="page-header">
<h1><i class="bi bi-cpu"></i> Hardware Coverage</h1>
<div class="header-actions">
<span class="badge badge-secondary badge-lg">{{ rows | length }} model{{ 's' if rows | length != 1 }} seen</span>
</div>
</div>
<p class="text-muted">
Every model that has booted WinPE here, as reported by the machine itself (WMI model, Dell system SKU,
BIOS version), checked against each image's driver map and the WinPE BIOS manifest. A model missing a
Win11 driver pack or a BIOS entry also shows on the Technician To-Do until it is added or dismissed.
</p>
<div class="section-card">
{% if rows %}
<div class="table-container">
<table class="data-table">
<thead>
<tr>
<th>Model (WMI)</th>
<th>System SKU</th>
<th>BIOS seen</th>
{% for image, os_label in images %}<th title="{{ image }}">{{ image | replace('gea-', '') }} <span class="text-muted">({{ os_label }})</span></th>{% endfor %}
<th>BIOS update</th>
<th>Last seen</th>
<th class="text-end"></th>
</tr>
</thead>
<tbody>
{% for r in rows %}
<tr title="Serials: {{ r.serials | join(', ') }}{% if r.pctypes %} | Types: {{ r.pctypes | join(', ') }}{% endif %}">
<td>
<span class="mono">{{ r.model }}</span>
{% if r.manufacturer %}<div class="small text-muted">{{ r.manufacturer }}</div>{% endif %}
</td>
<td class="mono">{{ r.skus | join(', ') or '-' }}</td>
<td class="mono">{{ r.last_bios_version or '-' }}</td>
{% for image, os_label in images %}<td>{{ driver_badge(r.drivers[image]) }}{{ update_hint(hints.drivers, r.drivers[image].file) }}</td>{% endfor %}
<td>{{ bios_badge(r.bios) }}{{ update_hint(hints.bios, r.bios.file) }}</td>
<td class="mono text-nowrap">{{ r.last_seen | local_dt }}<div class="small text-muted">{{ r.count }} boot{{ 's' if r.count != 1 }}</div></td>
<td class="text-end text-nowrap">
{% if r.gap %}
<form method="post" action="{{ url_for('hardware_dismiss') }}" style="display:inline;">
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
<input type="hidden" name="model" value="{{ r.model }}">
<input type="hidden" name="done" value="{{ '0' if r.dismissed else '1' }}">
<button type="submit" class="pxe-btn pxe-btn-ghost btn-row-action">{{ 'Reopen' if r.dismissed else 'Dismiss' }}</button>
</form>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center text-muted py-5">
<p class="mb-1">No machines have reported yet.</p>
<p class="small">Models appear here the next time a machine boots WinPE from this server.</p>
</div>
{% endif %}
</div>
{% endblock %}