fix(admin): resolve Low code-review findings (Admin-010,011,012)

- Admin-010: vendor Bootstrap 5.3.3 (CSS + JS bundle + maps + provenance
  README) under wwwroot/lib/bootstrap and reference local paths from
  App.razor — Admin no longer pulls Bootstrap from jsDelivr.
- Admin-011: swap FleetStatusPoller's three plain dictionaries for
  ConcurrentDictionary so ResetCache can't race a poll tick.
- Admin-012: drop the EquipmentId column from EquipmentCsvImporter (per
  admin-ui.md — equipment id is system-derived from EquipmentUuid);
  EquipmentImportBatchService and the textarea placeholder updated to
  match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph Doherty
2026-05-23 07:24:07 -04:00
parent 3f01a24b45
commit 2b33b64a58
16 changed files with 355 additions and 48 deletions
@@ -6,14 +6,16 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>OtOpcUa Admin</title>
<base href="/"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"/>
@* Admin-010: Bootstrap 5 is vendored under wwwroot/lib/bootstrap/ per admin-ui.md
"Tech Stack" — no public-CDN dependency so air-gapped fleet deployments work. *@
<link rel="stylesheet" href="lib/bootstrap/css/bootstrap.min.css"/>
<link rel="stylesheet" href="theme.css"/>
<link rel="stylesheet" href="app.css"/>
<HeadOutlet/>
</head>
<body>
<Routes/>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="lib/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="_framework/blazor.web.js"></script>
</body>
</html>
@@ -79,7 +79,7 @@
<div class="mt-3">
<label class="form-label">CSV content (paste or uploaded)</label>
<textarea class="form-control mono" rows="8" @bind="_csvText"
placeholder="# OtOpcUaCsv v1&#10;ZTag,MachineCode,SAPID,EquipmentId,…"/>
placeholder="# OtOpcUaCsv v1&#10;ZTag,MachineCode,SAPID,EquipmentUuid,Name,…"/>
</div>
<div class="mt-3">
<button class="btn btn-sm btn-outline-primary" @onclick="ParseAsync" disabled="@_busy">Parse</button>