- Dashboard: line charts (assets over time, components total + uninstalled)
with filled areas, shared x-axis (Mon YYYY), auto-formatted y-labels (1k/1M)
and global start date derived from earliest FirstSeenAt across components
- /ui/ingest/history: source type chips (Ingest / CSV Import / Manual / System)
- /ui/component/models: firmware version count column, column filters,
sortable headers, vendor distribution pie chart
- /ui/component/{vendor}/{model}: firmware version summary table with
per-version healthy/unknown/failed counts, failed rows highlighted
- /ui/component/uninstalled: new page + nav item; components not installed
on any server, two-level grouping by vendor then model (collapsed by default)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
66 lines
2.8 KiB
Cheetah
66 lines
2.8 KiB
Cheetah
{{define "components_uninstalled"}}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
{{template "head" .}}
|
|
<body>
|
|
{{template "topbar" .}}
|
|
{{template "breadcrumbs" .}}
|
|
|
|
<main class="container">
|
|
<section class="card">
|
|
<h2>Uninstalled Components</h2>
|
|
<div class="meta" style="margin-bottom:16px;">Components not currently installed in any server. Grouped by vendor, then by model.</div>
|
|
|
|
{{if .VendorGroups}}
|
|
{{range .VendorGroups}}
|
|
<details style="margin-bottom:12px; border:1px solid #e5e7eb; border-radius:10px; overflow:hidden;">
|
|
<summary style="list-style:none; cursor:pointer; padding:12px 16px; background:#f8fafc; display:flex; align-items:center; justify-content:space-between; gap:12px;">
|
|
<div style="font-weight:600; font-size:14px;">{{.Vendor}}</div>
|
|
<div class="timeline-card-badges">
|
|
<span class="timeline-card-badge">{{.Total}} components</span>
|
|
<span class="timeline-card-badge">{{len .ModelGroups}} models</span>
|
|
</div>
|
|
</summary>
|
|
<div style="padding:12px 16px; display:flex; flex-direction:column; gap:10px;">
|
|
{{range .ModelGroups}}
|
|
<details style="border:1px solid #e5e7eb; border-radius:8px; overflow:hidden;">
|
|
<summary style="list-style:none; cursor:pointer; padding:8px 12px; background:#f1f5f9; display:flex; align-items:center; justify-content:space-between; gap:12px;">
|
|
<span style="font-weight:500; font-size:13px;">{{.Model}}</span>
|
|
<span class="timeline-card-badge">{{len .Components}}</span>
|
|
</summary>
|
|
<div style="padding:8px 0;">
|
|
<table class="table" data-disable-auto-filters="true">
|
|
<thead>
|
|
<tr>
|
|
<th>Status</th>
|
|
<th>Vendor Serial</th>
|
|
<th>Vendor</th>
|
|
<th>Model</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .Components}}
|
|
<tr class="clickable" onclick="navigateToRow('{{.URL}}')">
|
|
<td><span class="badge {{componentStatusClass .Status}}">{{componentStatusText .Status}}</span></td>
|
|
<td><a href="{{.URL}}" onclick="event.stopPropagation();">{{.Component.VendorSerial}}</a></td>
|
|
<td>{{if .Component.Vendor}}{{.Component.Vendor}}{{else}}—{{end}}</td>
|
|
<td>{{if .Component.Model}}{{.Component.Model}}{{else}}—{{end}}</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</details>
|
|
{{end}}
|
|
</div>
|
|
</details>
|
|
{{end}}
|
|
{{else}}
|
|
<div class="meta">No uninstalled components found — all components are currently installed.</div>
|
|
{{end}}
|
|
</section>
|
|
</main>
|
|
</body>
|
|
</html>
|
|
{{end}}
|