Lint / JS (eslint) (push) Successful in 10s
Lint / Python (flake8) (push) Successful in 57s
Lint / Notify on failure (push) Skipped
Lint / Deploy (push) Skipped
Security / Python Security (bandit) (push) Successful in 1m7s
Lint / Python (flake8) (pull_request) Successful in 59s
Test / Python Tests (pytest) (push) Successful in 1m22s
Lint / JS (eslint) (pull_request) Successful in 11s
Lint / Notify on failure (pull_request) Skipped
Lint / Deploy (pull_request) Skipped
Security / Python Security (bandit) (pull_request) Successful in 1m7s
Test / Python Tests (pytest) (pull_request) Successful in 1m28s
Replace the port blocks on device pages with SVG faceplates traced from reference images: Dream Machine Pro, USW Pro 24 PoE, USW Aggregation, USW Flex, USW Flex Mini, USP PDU Pro and UPS 2U Pro. Port LEDs use each model's documented colors, and ports show a cable or module when up. Remove SWITCH_LAYOUTS, which had wrong data: the aggregation switch was numbered across the rows instead of odd over even, and the USW Flex had an SFP cage it doesn't have. Models without a faceplate use plain blocks. Show PDU and UPS outlets with on/off state and auto power-cycle, and let the UPS page show its panel even though it reports no ports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
57 lines
2.5 KiB
HTML
57 lines
2.5 KiB
HTML
{% extends "base.html" %}
|
||
{% block title %}{{ device_name }} – GANDALF{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="lt-page-header">
|
||
<div>
|
||
<p class="g-page-sub"><a href="{{ url_for('index') }}">← Dashboard</a></p>
|
||
<h1 class="lt-page-title device-title">
|
||
<span id="device-dot" class="dot-unknown"></span>
|
||
<span>{{ device_name }}</span>
|
||
</h1>
|
||
<p class="g-page-sub" id="device-subtitle"></p>
|
||
</div>
|
||
<div id="device-actions" class="device-actions"></div>
|
||
</div>
|
||
|
||
<div id="device-root"><div class="link-loading">Loading device</div></div>
|
||
|
||
<!-- Outside device-root: auto-refresh must not reset the filter or port panel -->
|
||
<section class="g-section" id="device-ports" hidden>
|
||
<div class="g-section-header"><h2 class="g-section-title" id="device-ports-title">Ports</h2></div>
|
||
<div class="device-inspector" id="device-inspector">
|
||
<div class="device-chassis" id="device-chassis" role="region" aria-label="Front panel"></div>
|
||
<div class="inspector-panel" id="inspector-panel" role="complementary" aria-label="Port detail panel">
|
||
<div class="inspector-panel-inner" id="inspector-panel-inner"></div>
|
||
</div>
|
||
<div class="lt-frame device-port-table">
|
||
<span class="lt-frame-bl">╚</span>
|
||
<span class="lt-frame-br">╝</span>
|
||
<div class="lt-toolbar device-toolbar">
|
||
<div class="lt-toolbar-left">
|
||
<div class="lt-search">
|
||
<input type="search" class="lt-input lt-search-input lt-search-input--sm" id="device-table-search"
|
||
placeholder="Filter…" autocomplete="off" aria-label="Filter ports">
|
||
</div>
|
||
<div class="sev-pills" role="group" aria-label="Filter by state">
|
||
<button type="button" class="pill active" data-device-filter="all" aria-pressed="true">All</button>
|
||
<button type="button" class="pill" data-device-filter="up" aria-pressed="false">Up</button>
|
||
<button type="button" class="pill" data-device-filter="problems" aria-pressed="false">Errors (<span id="device-error-count">0</span>)</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div id="device-table-wrap"></div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
{% include "_modem_panel.html" %}
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>const DEVICE_NAME = {{ device_name | tojson }};</script>
|
||
<script src="{{ url_for('static', filename='faceplates.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='port-inspector.js') }}"></script>
|
||
<script src="{{ url_for('static', filename='device.js') }}"></script>
|
||
{% endblock %}
|