Add terminal-style scan log panel
scan_state now accumulates log_lines per switch result. The status bar is replaced with a dark terminal panel showing a summary header [done/total ✓ok ✗fail | now: hostname] and a scrolling per-switch log with green/red colouring and timestamps. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+49
-13
@@ -382,18 +382,40 @@ var Xr=function(e){if(!(this instanceof Xr))return new Xr(e);this.id="Thenable/1
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ── Scan status bar ── */
|
/* ── Scan status bar ── */
|
||||||
.status-bar {
|
.scan-log {
|
||||||
display: none;
|
display: none;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #0d1117;
|
||||||
|
border-top: 1px solid #30363d;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.scan-log.visible { display: flex; }
|
||||||
|
.scan-log-header {
|
||||||
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 8px 16px;
|
padding: 6px 14px;
|
||||||
background: rgba(79,142,247,.08);
|
background: #161b22;
|
||||||
border-top: 1px solid rgba(79,142,247,.2);
|
border-bottom: 1px solid #21262d;
|
||||||
font-size: 12px;
|
|
||||||
color: var(--accent);
|
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
.status-bar.visible { display: flex; }
|
.scan-log-summary { color: #58a6ff; }
|
||||||
|
.scan-log-summary .ok-count { color: #3fb950; font-weight: 600; }
|
||||||
|
.scan-log-summary .fail-count { color: #f85149; font-weight: 600; }
|
||||||
|
.scan-log-body {
|
||||||
|
max-height: 140px;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 4px 14px 6px;
|
||||||
|
}
|
||||||
|
.scan-log-line {
|
||||||
|
padding: 1px 0;
|
||||||
|
color: #8b949e;
|
||||||
|
white-space: pre;
|
||||||
|
}
|
||||||
|
.scan-log-line.ok { color: #3fb950; }
|
||||||
|
.scan-log-line.fail { color: #f85149; }
|
||||||
.spinner {
|
.spinner {
|
||||||
width: 14px; height: 14px;
|
width: 14px; height: 14px;
|
||||||
border: 2px solid rgba(79,142,247,.3);
|
border: 2px solid rgba(79,142,247,.3);
|
||||||
@@ -560,10 +582,13 @@ var Xr=function(e){if(!(this instanceof Xr))return new Xr(e);this.id="Thenable/1
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Status bar -->
|
<!-- Scan log panel -->
|
||||||
<div class="status-bar" id="statusBar">
|
<div class="scan-log" id="statusBar">
|
||||||
<div class="spinner"></div>
|
<div class="scan-log-header">
|
||||||
<span id="statusText">Scanning...</span>
|
<div class="spinner"></div>
|
||||||
|
<span id="statusText" class="scan-log-summary">Scanning...</span>
|
||||||
|
</div>
|
||||||
|
<div class="scan-log-body" id="scanLogBody"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
@@ -915,8 +940,19 @@ async function pollStatus() {
|
|||||||
const pct = s.total > 0 ? Math.round((s.done / s.total) * 100) : 0;
|
const pct = s.total > 0 ? Math.round((s.done / s.total) * 100) : 0;
|
||||||
progressBar.style.width = pct + '%';
|
progressBar.style.width = pct + '%';
|
||||||
|
|
||||||
const host = s.current_hostname || s.current_ip || '...';
|
const host = s.current_hostname || s.current_ip || '…';
|
||||||
statusText.textContent = `Scanning ${host} — ${s.done}/${s.total} switches`;
|
statusText.innerHTML =
|
||||||
|
`[${s.done}/${s.total}] ` +
|
||||||
|
`<span class="ok-count">✓ ${s.ok}</span> ` +
|
||||||
|
`<span class="fail-count">✗ ${s.fail}</span>` +
|
||||||
|
` | now: ${host}`;
|
||||||
|
|
||||||
|
const logBody = document.getElementById('scanLogBody');
|
||||||
|
const lines = s.log_lines || [];
|
||||||
|
logBody.innerHTML = lines.map(l =>
|
||||||
|
`<div class="scan-log-line ${l.ok ? 'ok' : 'fail'}"><span style="color:#484f58">${l.ts} </span>${l.text}</div>`
|
||||||
|
).join('');
|
||||||
|
logBody.scrollTop = logBody.scrollHeight;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (isScanning) {
|
if (isScanning) {
|
||||||
|
|||||||
+15
-3
@@ -21,6 +21,7 @@ scan_state = {
|
|||||||
"ok": 0,
|
"ok": 0,
|
||||||
"fail": 0,
|
"fail": 0,
|
||||||
"errors": [],
|
"errors": [],
|
||||||
|
"log_lines": [],
|
||||||
"last_scan": None,
|
"last_scan": None,
|
||||||
"dept_filter": None, # None = all, "ELEC" or "GW" = dept-only
|
"dept_filter": None, # None = all, "ELEC" or "GW" = dept-only
|
||||||
}
|
}
|
||||||
@@ -56,6 +57,7 @@ def run_scan(dept: str = None, workers: int = 5, login_delay: int = 3):
|
|||||||
"ok": 0,
|
"ok": 0,
|
||||||
"fail": 0,
|
"fail": 0,
|
||||||
"errors": [],
|
"errors": [],
|
||||||
|
"log_lines": [],
|
||||||
"dept_filter": dept,
|
"dept_filter": dept,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -63,6 +65,8 @@ def run_scan(dept: str = None, workers: int = 5, login_delay: int = 3):
|
|||||||
clear_links() # Fresh start for links each scan
|
clear_links() # Fresh start for links each scan
|
||||||
|
|
||||||
def on_progress(done, total, ip, result):
|
def on_progress(done, total, ip, result):
|
||||||
|
from datetime import datetime
|
||||||
|
ts = datetime.now().strftime("%H:%M:%S")
|
||||||
scan_state["done"] = done
|
scan_state["done"] = done
|
||||||
scan_state["total"] = total
|
scan_state["total"] = total
|
||||||
scan_state["current_ip"] = ip
|
scan_state["current_ip"] = ip
|
||||||
@@ -70,6 +74,12 @@ def run_scan(dept: str = None, workers: int = 5, login_delay: int = 3):
|
|||||||
if result["success"]:
|
if result["success"]:
|
||||||
scan_state["ok"] += 1
|
scan_state["ok"] += 1
|
||||||
scan_state["current_hostname"] = result.get("hostname", ip)
|
scan_state["current_hostname"] = result.get("hostname", ip)
|
||||||
|
vendor = result.get("vendor", "")
|
||||||
|
n = len(result.get("neighbors", []))
|
||||||
|
scan_state["log_lines"].append({
|
||||||
|
"ts": ts, "ok": True,
|
||||||
|
"text": f"✓ {result['hostname']} ({ip}) [{vendor}] — {n} neighbor{'s' if n != 1 else ''}",
|
||||||
|
})
|
||||||
|
|
||||||
upsert_switch(
|
upsert_switch(
|
||||||
chassis_id=result["chassis_id"],
|
chassis_id=result["chassis_id"],
|
||||||
@@ -100,9 +110,11 @@ def run_scan(dept: str = None, workers: int = 5, login_delay: int = 3):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
scan_state["fail"] += 1
|
scan_state["fail"] += 1
|
||||||
scan_state["errors"].append({
|
error = result.get("error", "Unknown error")
|
||||||
"ip": ip,
|
scan_state["errors"].append({"ip": ip, "error": error})
|
||||||
"error": result.get("error", "Unknown error")
|
scan_state["log_lines"].append({
|
||||||
|
"ts": ts, "ok": False,
|
||||||
|
"text": f"✗ {ip} — {error}",
|
||||||
})
|
})
|
||||||
|
|
||||||
scan_all_switches(switches, progress_callback=on_progress, max_workers=workers, login_delay=login_delay)
|
scan_all_switches(switches, progress_callback=on_progress, max_workers=workers, login_delay=login_delay)
|
||||||
|
|||||||
Reference in New Issue
Block a user