Files
gandalf/templates/rack.html
T
jaredandClaude Opus 5.5 bdd68a397d
Lint / JS (eslint) (push) Successful in 7s
Lint / Python (flake8) (push) Successful in 48s
Lint / Notify on failure (push) Skipped
Lint / Deploy (push) Skipped
Security / Python Security (bandit) (push) Successful in 49s
Lint / Python (flake8) (pull_request) Successful in 51s
Test / Python Tests (pytest) (push) Successful in 1m2s
Lint / JS (eslint) (pull_request) Successful in 7s
Lint / Notify on failure (pull_request) Skipped
Lint / Deploy (pull_request) Skipped
Security / Python Security (bandit) (pull_request) Successful in 50s
Test / Python Tests (pytest) (pull_request) Successful in 53s
Rack: link items to devices, shelves, several racks, export; fix layout and light mode
Cutsheet items gain a "Gandalf device" link, so an item named after the
product (UDM-Pro) shows the live device's faceplate, ports and status.
Cable checks, suggestions, tickets and the device page treat an item and
its linked device as one. Without this, product-named items drew as bare
name plates.

Items can sit on a shelf instead of a rack unit; the shelf draws what is
on it with live status. Items have a rack, the page shows a tab per rack
(config "racks"), and a rack can be downloaded as SVG or PNG.

The rack is centred, long runs of empty units fold into one band (with a
toggle), every device fills the 19" width, the UPS shows its front only,
and the rack keeps its own palette so it reads in light mode.

New cutsheet_items columns rack, shelf and device are added on first use.
Deleting a shelf, or making it something else, is refused while it holds
items; renaming it carries over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-10 21:44:59 -05:00

44 lines
1.9 KiB
HTML

{% extends "base.html" %}
{% block title %}Rack{% endblock %}
{% block content %}
<div class="lt-page-header">
<div>
<h1 class="lt-page-title">Rack</h1>
<p class="g-page-sub">The rack front, drawn from the rack units on the cutsheet with live port state. Hover a port to light up every port on the same cable run; click it to open the port or the cable.</p>
</div>
<div class="cs-actions no-print">
<button type="button" class="lt-btn lt-btn-secondary lt-btn-sm" data-export="svg">Download SVG</button>
<button type="button" class="lt-btn lt-btn-secondary lt-btn-sm" data-export="png">Download PNG</button>
{% if can_edit %}
<a class="lt-btn lt-btn-secondary lt-btn-sm" href="/cutsheet#cs-items-section">Edit positions</a>
{% endif %}
</div>
</div>
<div class="rack-tabs" id="rack-tabs" role="tablist" aria-label="Racks" hidden></div>
<div class="rack-warnings" id="rack-warnings" role="alert" hidden></div>
<section class="g-section">
<div class="g-section-header">
<h2 class="g-section-title" id="rack-title">Front</h2>
<span class="g-section-badge" id="rack-count">0</span>
</div>
<p class="rack-readout" id="rack-readout" aria-live="polite"></p>
<div class="rack-legend" aria-hidden="true">
<span><i class="rack-key rack-key-ok"></i>matches cutsheet</span>
<span><i class="rack-key rack-key-bad"></i>mismatch</span>
<span><i class="rack-key rack-key-doc"></i>documented, unconfirmed</span>
<label class="rack-toggle"><input type="checkbox" id="rack-show-empty"> Show empty units</label>
</div>
<div class="rack" id="rack"><div class="link-loading">Loading rack</div></div>
<p class="cs-hint rack-unplaced" id="rack-unplaced"></p>
</section>
{% endblock %}
{% block scripts %}
<script src="{{ url_for('static', filename='faceplates.js') }}"></script>
<script src="{{ url_for('static', filename='rack.js') }}"></script>
{% endblock %}