Restructure app to use LotusGuild Terminal Design System v1.2
Lint / Python (flake8) (push) Failing after 45s
Lint / JS (eslint) (push) Successful in 7s
Security / Python Security (bandit) (push) Failing after 1m22s
Test / Python Tests (pytest) (push) Successful in 51s
Lint / Notify on failure (push) Successful in 2s
Lint / Deploy (push) Has been skipped

Replace custom phosphor-green terminal aesthetic with the lt-* component
system from base.css/base.js. All templates now inherit the LotusGuild
multi-accent Anduril palette via variable aliases in style.css, and use
lt-header, lt-nav, lt-card, lt-table, lt-btn, lt-modal, lt-badge etc.
Custom components (topology, inspector chassis, link debug, SFP panels)
are preserved with color values updated to base.css palette variables.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-18 21:01:20 -04:00
parent 2c4e8fcfda
commit e8de40250a
7 changed files with 1037 additions and 2438 deletions
+77 -73
View File
@@ -3,79 +3,82 @@
{% block content %}
<div class="page-header">
<h1 class="page-title">Alert Suppressions</h1>
<p class="page-sub">Manage maintenance windows and per-target alert suppression rules.</p>
<div class="g-page-header">
<h1 class="g-page-title">Alert Suppressions</h1>
<p class="g-page-sub">Manage maintenance windows and per-target alert suppression rules.</p>
</div>
<!-- ── Create suppression ─────────────────────────────────────────── -->
<section class="section">
<div class="section-header">
<h2 class="section-title">Create Suppression</h2>
<section class="g-section">
<div class="g-section-header">
<h2 class="g-section-title">Create Suppression</h2>
</div>
<div class="form-card">
<form id="create-suppression-form" onsubmit="createSuppression(event)">
<div class="form-row">
<div class="form-group">
<label for="s-type">Target Type <span class="required">*</span></label>
<select id="s-type" name="target_type" onchange="onTypeChange()">
<option value="host">Host (all interfaces)</option>
<option value="interface">Specific Interface</option>
<option value="unifi_device">UniFi Device</option>
<option value="all">Global (suppress everything)</option>
</select>
</div>
<div class="form-group" id="name-group">
<label for="s-name">Target Name <span class="required">*</span></label>
<input type="text" id="s-name" name="target_name"
placeholder="hostname or device name" autocomplete="off">
</div>
<div class="form-group" id="detail-group" style="display:none">
<label for="s-detail">Interface Name</label>
<input type="text" id="s-detail" name="target_detail"
placeholder="e.g. enp35s0 or bond0" autocomplete="off">
</div>
</div>
<div class="form-row">
<div class="form-group form-group-wide">
<label for="s-reason">Reason <span class="required">*</span></label>
<input type="text" id="s-reason" name="reason"
placeholder="e.g. Planned switch maintenance, replacing SFP on large1/enp43s0"
required>
</div>
</div>
<div class="form-row form-row-align">
<div class="form-group">
<label>Duration</label>
<div class="duration-pills">
<button type="button" class="pill" onclick="setDur(30, this)">30 min</button>
<button type="button" class="pill" onclick="setDur(60, this)">1 hr</button>
<button type="button" class="pill" onclick="setDur(240, this)">4 hr</button>
<button type="button" class="pill" onclick="setDur(480, this)">8 hr</button>
<button type="button" class="pill pill-manual active" onclick="setDur(null, this)">Manual ∞</button>
<div class="lt-card">
<div class="lt-card-body">
<form id="create-suppression-form" onsubmit="createSuppression(event)">
<div class="form-row">
<div class="lt-form-group">
<label class="lt-label" for="s-type">Target Type <span class="required">*</span></label>
<select class="lt-select" id="s-type" name="target_type" onchange="onTypeChange()">
<option value="host">Host (all interfaces)</option>
<option value="interface">Specific Interface</option>
<option value="unifi_device">UniFi Device</option>
<option value="all">Global (suppress everything)</option>
</select>
</div>
<div class="lt-form-group" id="name-group">
<label class="lt-label" for="s-name">Target Name <span class="required">*</span></label>
<input type="text" class="lt-input" id="s-name" name="target_name"
placeholder="hostname or device name" autocomplete="off">
</div>
<div class="lt-form-group" id="detail-group" style="display:none">
<label class="lt-label" for="s-detail">Interface Name</label>
<input type="text" class="lt-input" id="s-detail" name="target_detail"
placeholder="e.g. enp35s0 or bond0" autocomplete="off">
</div>
<input type="hidden" id="s-expires" name="expires_minutes" value="">
<div class="form-hint" id="s-dur-hint">Persists until manually removed.</div>
</div>
<div class="form-group form-group-submit">
<button type="submit" class="btn btn-primary btn-lg">🔕 Apply Suppression</button>
<div class="form-row">
<div class="lt-form-group form-group-wide">
<label class="lt-label" for="s-reason">Reason <span class="required">*</span></label>
<input type="text" class="lt-input" id="s-reason" name="reason"
placeholder="e.g. Planned switch maintenance, replacing SFP on large1/enp43s0"
required>
</div>
</div>
</div>
</form>
<div class="form-row form-row-align">
<div class="lt-form-group">
<label class="lt-label">Duration</label>
<div class="duration-pills">
<button type="button" class="pill" onclick="setDur(30, this)">30 min</button>
<button type="button" class="pill" onclick="setDur(60, this)">1 hr</button>
<button type="button" class="pill" onclick="setDur(240, this)">4 hr</button>
<button type="button" class="pill" onclick="setDur(480, this)">8 hr</button>
<button type="button" class="pill pill-manual active" onclick="setDur(null, this)">Manual ∞</button>
</div>
<input type="hidden" id="s-expires" name="expires_minutes" value="">
<div class="lt-field-hint" id="s-dur-hint">Persists until manually removed.</div>
</div>
<div class="lt-form-group form-group-submit">
<button type="submit" class="lt-btn lt-btn-primary lt-btn-lg">🔕 Apply Suppression</button>
</div>
</div>
</form>
</div>
</div>
</section>
<!-- ── Active suppressions ────────────────────────────────────────── -->
<section class="section">
<div class="section-header">
<h2 class="section-title">Active Suppressions</h2>
<span class="section-badge">{{ active | length }}</span>
<section class="g-section">
<div class="g-section-header">
<h2 class="g-section-title">Active Suppressions</h2>
<span class="g-section-badge">{{ active | length }}</span>
</div>
{% if active %}
<div class="table-wrap">
<table class="data-table" id="active-sup-table">
<div class="lt-table-wrap">
<table class="lt-table" id="active-sup-table">
<caption class="lt-sr-only">Active suppression rules</caption>
<thead>
<tr>
<th>Type</th><th>Target</th><th>Detail</th><th>Reason</th>
@@ -85,7 +88,7 @@
<tbody>
{% for s in active %}
<tr id="sup-row-{{ s.id }}">
<td><span class="badge badge-info">{{ s.target_type }}</span></td>
<td><span class="lt-badge badge-info">{{ s.target_type }}</span></td>
<td>{{ s.target_name or 'all' }}</td>
<td>{{ s.target_detail or '' }}</td>
<td>{{ s.reason }}</td>
@@ -93,7 +96,7 @@
<td class="ts-cell">{{ s.created_at }}</td>
<td class="ts-cell">{% if s.expires_at %}{{ s.expires_at }}{% else %}<em>manual</em>{% endif %}</td>
<td>
<button class="btn-sm btn-danger" onclick="removeSuppression({{ s.id }})">Remove</button>
<button class="lt-btn lt-btn-danger lt-btn-sm" onclick="removeSuppression({{ s.id }})">Remove</button>
</td>
</tr>
{% endfor %}
@@ -106,14 +109,15 @@
</section>
<!-- ── Suppression history ────────────────────────────────────────── -->
<section class="section">
<div class="section-header">
<h2 class="section-title">History</h2>
<span class="section-badge">{{ history | length }}</span>
<section class="g-section">
<div class="g-section-header">
<h2 class="g-section-title">History</h2>
<span class="g-section-badge">{{ history | length }}</span>
</div>
{% if history %}
<div class="table-wrap">
<table class="data-table data-table-sm">
<div class="lt-table-wrap">
<table class="lt-table lt-table-sm">
<caption class="lt-sr-only">Suppression history</caption>
<thead>
<tr>
<th>Type</th><th>Target</th><th>Detail</th><th>Reason</th>
@@ -132,9 +136,9 @@
<td class="ts-cell">{% if s.expires_at %}{{ s.expires_at }}{% else %}<em>manual</em>{% endif %}</td>
<td>
{% if s.active %}
<span class="badge badge-ok">Yes</span>
<span class="lt-badge badge-ok">Yes</span>
{% else %}
<span class="badge badge-neutral">No</span>
<span class="lt-badge badge-neutral">No</span>
{% endif %}
</td>
</tr>
@@ -148,9 +152,9 @@
</section>
<!-- ── Available targets reference ───────────────────────────────── -->
<section class="section">
<div class="section-header">
<h2 class="section-title">Available Targets</h2>
<section class="g-section">
<div class="g-section-header">
<h2 class="g-section-title">Available Targets</h2>
</div>
<div class="targets-grid">
{% for name, host in snapshot.hosts.items() %}