feat: add Repair Center operations view

This commit is contained in:
lussierj committed 2026-08-11 20:17:16 +00:00
1 parent 786a1ab910
commit 4a1959ecd6
14 files changed
+1963 -338

No files matched your search

+73 -14
View File
@@ -199,26 +199,79 @@ def _state_messages(noun: str) -> str:
"""
def _repairs_content() -> str:
def _repairs_content(can_view_locations: bool, can_view_miners: bool) -> str:
location_filters = """
<div class="field"><label for="repairSite">Site</label>
<select id="repairSite"><option value="">All sites</option></select></div>
<div class="field"><label for="repairRoom">Room</label>
<select id="repairRoom"><option value="">All rooms</option></select></div>
""" if can_view_locations else ""
search_placeholder = (
"Miner, model, status, reason, or context"
if can_view_miners else "Repair status, reason, or context"
)
model_filter = """
<div class="field"><label for="repairModel">Model</label>
<input id="repairModel" type="text" autocomplete="off" placeholder="Any model"></div>
""" if can_view_miners else ""
return f"""
<section class="panel" aria-labelledby="repairQueueTitle">
<section class="panel repair-center" aria-labelledby="repairQueueTitle">
<div class="panel-head">
<div>
<h2 id="repairQueueTitle">Current repair queue</h2>
<p class="panel-copy">Real records from the existing repair queue
API. Open a miner to continue in its current detail view.</p>
<div><h2 id="repairQueueTitle">Repair Center</h2>
<p class="panel-copy">Active work and historical modular repairs, with legacy queue records clearly identified.</p></div>
<span class="freshness" id="repairFreshness">Loading repair work</span>
</div>
<div class="repair-summary" aria-label="Repair summary">
<div><span>Total results</span><strong id="repairTotal">-</strong></div>
<div><span>Active</span><strong id="repairActive">-</strong></div>
<div><span>Historical</span><strong id="repairHistorical">-</strong></div>
</div>
<form class="repair-filters" id="repairFilters" role="search">
<div class="field repair-search"><label for="repairQuery">Search repairs</label>
<input id="repairQuery" type="search" autocomplete="off"
placeholder="{search_placeholder}"></div>
<div class="field"><label for="repairScope">Scope</label>
<select id="repairScope"><option value="active">Active</option>
<option value="historical">Historical</option><option value="all">All</option></select></div>
<div class="field"><label for="repairStatus">Repair status</label>
<select id="repairStatus"><option value="">All statuses</option></select></div>
{model_filter}
<div class="field"><label for="repairLifecycle">Miner lifecycle</label>
<select id="repairLifecycle"><option value="">All lifecycle states</option>
<option value="active">Active</option><option value="spare">Spare</option>
<option value="in_repair">In repair</option><option value="retired">Retired</option></select></div>
{location_filters}
<div class="repair-filter-actions">
<button class="command-button" type="submit">Apply</button>
<button class="quiet-button" id="repairReset" type="button">Reset</button>
</div>
<span class="freshness">Loaded on request</span>
</div>
</form>
{_state_messages("repair records")}
<div class="table-wrap" data-view-state="ready" hidden>
<table>
<thead><tr><th>Miner</th><th>Model</th><th>Repair state</th>
<th>Reported issue</th><th>Last update</th></tr></thead>
<tbody id="repairRows"></tbody>
</table>
<div data-view-state="ready" hidden>
<p class="repair-result-summary" id="repairResultSummary" aria-live="polite"></p>
<div class="table-wrap repair-table-wrap">
<table class="repair-table">
<thead><tr><th>Miner</th><th>Repair state</th><th>Reported problem</th>
<th>Latest context</th><th>Location</th><th>Opened / age</th>
<th>Parts</th><th>Actions</th></tr></thead>
<tbody id="repairRows"></tbody>
</table>
</div>
</div>
<nav class="repair-pagination" aria-label="Repair result pages">
<button class="quiet-button" id="repairPrevious" type="button" disabled>Previous</button>
<label for="repairLimit">Rows per page</label>
<select id="repairLimit"><option value="25">25</option><option value="50">50</option>
<option value="100">100</option><option value="250">250</option></select>
<button class="quiet-button" id="repairNext" type="button" disabled>Next</button>
</nav>
</section>
<aside class="repair-inspector" id="repairInspector" aria-labelledby="repairInspectorTitle" hidden>
<div class="inspector-head"><div><span class="eyebrow">Repair context</span>
<h2 id="repairInspectorTitle">Repair details</h2></div>
<button class="icon-button" id="repairInspectorClose" type="button" aria-label="Close repair details">X</button></div>
<div id="repairInspectorBody"></div>
</aside>
"""
@@ -338,6 +391,10 @@ def render_app_page(
if view == "map"
else _miners_content(has_permission("locations.view"))
if view == "miners"
else _repairs_content(
has_permission("locations.view"), has_permission("miners.view")
)
if view == "repairs"
else CONTENT[view]()
)
page_script = (
@@ -345,6 +402,8 @@ def render_app_page(
if view == "map"
else '<script src="/assets/minerops-fleet.js" defer></script>'
if view == "miners"
else '<script src="/assets/minerops-repair-center.js" defer></script>'
if view == "repairs"
else ""
)
return f"""<!doctype html>