|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>NetDiag: Host & Connection Monitor</title> |
|
|
|
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
|
|
|
|
|
<style> |
|
|
:root { |
|
|
--bg-color: #0f172a; |
|
|
--card-bg: rgba(30, 41, 59, 0.7); |
|
|
--card-border: rgba(148, 163, 184, 0.1); |
|
|
--text-primary: #f1f5f9; |
|
|
--text-secondary: #94a3b8; |
|
|
--accent-cyan: #06b6d4; |
|
|
--accent-green: #10b981; |
|
|
--accent-red: #ef4444; |
|
|
--accent-orange: #f59e0b; |
|
|
--glow: 0 0 15px rgba(6, 182, 212, 0.3); |
|
|
--font-main: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; |
|
|
} |
|
|
|
|
|
* { |
|
|
box-sizing: border-box; |
|
|
margin: 0; |
|
|
padding: 0; |
|
|
} |
|
|
|
|
|
body { |
|
|
font-family: var(--font-main); |
|
|
background-color: var(--bg-color); |
|
|
background-image: |
|
|
radial-gradient(at 0% 0%, rgba(6, 182, 212, 0.15) 0px, transparent 50%), |
|
|
radial-gradient(at 100% 100%, rgba(16, 185, 129, 0.15) 0px, transparent 50%); |
|
|
color: var(--text-primary); |
|
|
min-height: 100vh; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
overflow-x: hidden; |
|
|
} |
|
|
|
|
|
|
|
|
header { |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
align-items: center; |
|
|
padding: 1.5rem 2rem; |
|
|
border-bottom: 1px solid var(--card-border); |
|
|
backdrop-filter: blur(10px); |
|
|
position: sticky; |
|
|
top: 0; |
|
|
z-index: 100; |
|
|
background: rgba(15, 23, 42, 0.8); |
|
|
} |
|
|
|
|
|
.brand { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 0.75rem; |
|
|
font-size: 1.5rem; |
|
|
font-weight: 700; |
|
|
color: var(--accent-cyan); |
|
|
text-shadow: 0 0 10px rgba(6, 182, 212, 0.4); |
|
|
} |
|
|
|
|
|
.brand i { |
|
|
font-size: 1.8rem; |
|
|
} |
|
|
|
|
|
.anycoder-link { |
|
|
font-size: 0.9rem; |
|
|
color: var(--text-secondary); |
|
|
text-decoration: none; |
|
|
padding: 0.5rem 1rem; |
|
|
border: 1px solid var(--card-border); |
|
|
border-radius: 20px; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.anycoder-link:hover { |
|
|
color: var(--text-primary); |
|
|
border-color: var(--accent-cyan); |
|
|
box-shadow: var(--glow); |
|
|
} |
|
|
|
|
|
|
|
|
main { |
|
|
flex: 1; |
|
|
padding: 2rem; |
|
|
max-width: 1400px; |
|
|
margin: 0 auto; |
|
|
width: 100%; |
|
|
display: grid; |
|
|
grid-template-columns: repeat(12, 1fr); |
|
|
gap: 1.5rem; |
|
|
} |
|
|
|
|
|
|
|
|
.card { |
|
|
background: var(--card-bg); |
|
|
border: 1px solid var(--card-border); |
|
|
border-radius: 16px; |
|
|
padding: 1.5rem; |
|
|
backdrop-filter: blur(12px); |
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
transition: transform 0.2s ease, box-shadow 0.2s ease; |
|
|
} |
|
|
|
|
|
.card:hover { |
|
|
transform: translateY(-2px); |
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2); |
|
|
} |
|
|
|
|
|
.card-header { |
|
|
display: flex; |
|
|
justify-content: space-between; |
|
|
align-items: center; |
|
|
margin-bottom: 1rem; |
|
|
} |
|
|
|
|
|
.card-title { |
|
|
font-size: 1rem; |
|
|
font-weight: 600; |
|
|
color: var(--text-secondary); |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 0.5rem; |
|
|
} |
|
|
|
|
|
|
|
|
.status-panel { |
|
|
grid-column: span 12; |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); |
|
|
gap: 1.5rem; |
|
|
} |
|
|
|
|
|
.chart-panel { |
|
|
grid-column: span 8; |
|
|
min-height: 400px; |
|
|
} |
|
|
|
|
|
.log-panel { |
|
|
grid-column: span 4; |
|
|
min-height: 400px; |
|
|
overflow: hidden; |
|
|
} |
|
|
|
|
|
.controls-panel { |
|
|
grid-column: span 12; |
|
|
display: flex; |
|
|
justify-content: flex-end; |
|
|
gap: 1rem; |
|
|
align-items: center; |
|
|
} |
|
|
|
|
|
|
|
|
.metric-value { |
|
|
font-size: 2.5rem; |
|
|
font-weight: 700; |
|
|
margin: 0.5rem 0; |
|
|
} |
|
|
|
|
|
.metric-unit { |
|
|
font-size: 1rem; |
|
|
color: var(--text-secondary); |
|
|
font-weight: 400; |
|
|
} |
|
|
|
|
|
.status-indicator { |
|
|
width: 12px; |
|
|
height: 12px; |
|
|
border-radius: 50%; |
|
|
background-color: var(--text-secondary); |
|
|
box-shadow: 0 0 10px currentColor; |
|
|
transition: background-color 0.3s ease, box-shadow 0.3s ease; |
|
|
} |
|
|
|
|
|
.status-indicator.active { background-color: var(--accent-green); color: var(--accent-green); } |
|
|
.status-indicator.warning { background-color: var(--accent-orange); color: var(--accent-orange); } |
|
|
.status-indicator.critical { background-color: var(--accent-red); color: var(--accent-red); } |
|
|
|
|
|
|
|
|
.progress-container { |
|
|
width: 100%; |
|
|
height: 8px; |
|
|
background: rgba(255, 255, 255, 0.1); |
|
|
border-radius: 4px; |
|
|
overflow: hidden; |
|
|
margin-top: 0.5rem; |
|
|
} |
|
|
|
|
|
.progress-bar { |
|
|
height: 100%; |
|
|
width: 0%; |
|
|
background: var(--accent-cyan); |
|
|
border-radius: 4px; |
|
|
transition: width 0.5s ease, background-color 0.3s ease; |
|
|
position: relative; |
|
|
} |
|
|
|
|
|
.progress-bar::after { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
top: 0; left: 0; right: 0; bottom: 0; |
|
|
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent); |
|
|
transform: translateX(-100%); |
|
|
animation: shimmer 2s infinite; |
|
|
} |
|
|
|
|
|
@keyframes shimmer { |
|
|
100% { transform: translateX(100%); } |
|
|
} |
|
|
|
|
|
|
|
|
canvas { |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
display: block; |
|
|
} |
|
|
|
|
|
|
|
|
.log-container { |
|
|
font-family: 'Courier New', monospace; |
|
|
font-size: 0.85rem; |
|
|
color: var(--text-secondary); |
|
|
overflow-y: auto; |
|
|
flex: 1; |
|
|
padding-right: 0.5rem; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
gap: 0.25rem; |
|
|
} |
|
|
|
|
|
.log-entry { |
|
|
display: flex; |
|
|
gap: 0.5rem; |
|
|
} |
|
|
|
|
|
.log-time { color: var(--accent-cyan); } |
|
|
.log-msg-info { color: var(--text-primary); } |
|
|
.log-msg-warn { color: var(--accent-orange); } |
|
|
.log-msg-err { color: var(--accent-red); } |
|
|
|
|
|
|
|
|
.btn { |
|
|
padding: 0.75rem 1.5rem; |
|
|
border-radius: 8px; |
|
|
border: none; |
|
|
font-weight: 600; |
|
|
cursor: pointer; |
|
|
transition: all 0.2s ease; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 0.5rem; |
|
|
font-size: 0.95rem; |
|
|
} |
|
|
|
|
|
.btn-primary { |
|
|
background: var(--accent-cyan); |
|
|
color: #0f172a; |
|
|
} |
|
|
|
|
|
.btn-primary:hover { |
|
|
background: #22d3ee; |
|
|
box-shadow: 0 0 15px rgba(6, 182, 212, 0.5); |
|
|
} |
|
|
|
|
|
.btn-danger { |
|
|
background: transparent; |
|
|
border: 1px solid var(--accent-red); |
|
|
color: var(--accent-red); |
|
|
} |
|
|
|
|
|
.btn-danger:hover { |
|
|
background: rgba(239, 68, 68, 0.1); |
|
|
} |
|
|
|
|
|
|
|
|
#toast-container { |
|
|
position: fixed; |
|
|
bottom: 2rem; |
|
|
right: 2rem; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
gap: 1rem; |
|
|
z-index: 1000; |
|
|
} |
|
|
|
|
|
.toast { |
|
|
background: rgba(15, 23, 42, 0.95); |
|
|
border-left: 4px solid var(--accent-cyan); |
|
|
padding: 1rem 1.5rem; |
|
|
border-radius: 4px; |
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5); |
|
|
color: var(--text-primary); |
|
|
transform: translateX(120%); |
|
|
transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55); |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 0.75rem; |
|
|
backdrop-filter: blur(5px); |
|
|
} |
|
|
|
|
|
.toast.show { |
|
|
transform: translateX(0); |
|
|
} |
|
|
|
|
|
|
|
|
@media (max-width: 1024px) { |
|
|
.chart-panel { grid-column: span 12; } |
|
|
.log-panel { grid-column: span 12; min-height: 250px; } |
|
|
} |
|
|
|
|
|
@media (max-width: 600px) { |
|
|
header { flex-direction: column; gap: 1rem; } |
|
|
.metric-value { font-size: 2rem; } |
|
|
.controls-panel { flex-direction: column; align-items: stretch; } |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body> |
|
|
|
|
|
<header> |
|
|
<div class="brand"> |
|
|
<i class="fa-solid fa-network-wired"></i> |
|
|
<span>NetDiag</span> |
|
|
</div> |
|
|
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="anycoder-link"> |
|
|
Built with anycoder <i class="fa-solid fa-arrow-up-right-from-square" style="font-size: 0.7em; margin-left:4px;"></i> |
|
|
</a> |
|
|
</header> |
|
|
|
|
|
<main> |
|
|
|
|
|
<section class="status-panel"> |
|
|
|
|
|
|
|
|
<div class="card"> |
|
|
<div class="card-header"> |
|
|
<div class="card-title"> |
|
|
<i class="fa-solid fa-server"></i> Host CPU Load |
|
|
</div> |
|
|
<div id="host-status-light" class="status-indicator active"></div> |
|
|
</div> |
|
|
<div class="metric-value" id="cpu-val">0%</div> |
|
|
<div class="progress-container"> |
|
|
<div id="cpu-bar" class="progress-bar"></div> |
|
|
</div> |
|
|
<div style="margin-top: 0.5rem; font-size: 0.8rem; color: var(--text-secondary);"> |
|
|
Limit: 90% (Throttling Threshold) |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="card"> |
|
|
<div class="card-header"> |
|
|
<div class="card-title"> |
|
|
<i class="fa-solid fa-memory"></i> Memory Usage |
|
|
</div> |
|
|
</div> |
|
|
<div class="metric-value" id="ram-val">0<span class="metric-unit">GB</span></div> |
|
|
<div class="progress-container"> |
|
|
<div id="ram-bar" class="progress-bar" style="background-color: var(--accent-green);"></div> |
|
|
</div> |
|
|
<div style="margin-top: 0.5rem; font-size: 0.8rem; color: var(--text-secondary);"> |
|
|
Total: 16 GB |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="card"> |
|
|
<div class="card-header"> |
|
|
<div class="card-title"> |
|
|
<i class="fa-solid fa-wifi"></i> Connection Latency |
|
|
</div> |
|
|
<div id="conn-status-light" class="status-indicator active"></div> |
|
|
</div> |
|
|
<div class="metric-value" id="ping-val">0<span class="metric-unit">ms</span></div> |
|
|
<div class="progress-container"> |
|
|
<div id="ping-bar" class="progress-bar" style="background-color: var(--accent-orange);"></div> |
|
|
</div> |
|
|
<div style="margin-top: 0.5rem; font-size: 0.8rem; color: var(--text-secondary);"> |
|
|
Jitter: <span id="jitter-val">0</span>ms |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
</section> |
|
|
|
|
|
|
|
|
<section class="card chart-panel"> |
|
|
<div class="card-header"> |
|
|
<div class="card-title"> |
|
|
<i class="fa-solid fa-chart-line"></i> Real-Time Traffic Analysis |
|
|
</div> |
|
|
<div style="font-size: 0.8rem; color: var(--text-secondary);"> |
|
|
<span style="color: var(--accent-cyan)">●</span> Requests |
|
|
<span style="color: var(--accent-red)">●</span> Errors |
|
|
</div> |
|
|
</div> |
|
|
<div style="flex: 1; position: relative;"> |
|
|
<canvas id="trafficChart"></canvas> |
|
|
</div> |
|
|
</section> |
|
|
|
|
|
|
|
|
<section class="card log-panel"> |
|
|
<div class="card-header"> |
|
|
<div class="card-title"> |
|
|
<i class="fa-solid fa-terminal"></i> System Logs |
|
|
</div> |
|
|
<button onclick="clearLogs()" style="background:none; border:none; color:var(--text-secondary); cursor:pointer;"> |
|
|
<i class="fa-solid fa-trash"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="log-container" id="log-container"> |
|
|
|
|
|
</div> |
|
|
</section> |
|
|
|
|
|
|
|
|
<section class="controls-panel"> |
|
|
<button class="btn btn-danger" id="stop-btn" onclick="toggleMonitoring(false)" disabled> |
|
|
<i class="fa-solid fa-stop"></i> Stop Monitor |
|
|
</button> |
|
|
<button class="btn btn-primary" id="start-btn" onclick="toggleMonitoring(true)"> |
|
|
<i class="fa-solid fa-play"></i> Start Diagnostics |
|
|
</button> |
|
|
<button class="btn btn-primary" style="background: var(--accent-orange);" onclick="simulateSpike()"> |
|
|
<i class="fa-solid fa-bolt"></i> Test Host Limit |
|
|
</button> |
|
|
</section> |
|
|
|
|
|
</main> |
|
|
|
|
|
|
|
|
<div id="toast-container"></div> |
|
|
|
|
|
<script> |
|
|
|
|
|
let isRunning = false; |
|
|
let intervalId = null; |
|
|
let chartIntervalId = null; |
|
|
|
|
|
|
|
|
const maxDataPoints = 60; |
|
|
let trafficData = new Array(maxDataPoints).fill(0); |
|
|
let errorData = new Array(maxDataPoints).fill(0); |
|
|
|
|
|
|
|
|
const cpuVal = document.getElementById('cpu-val'); |
|
|
const cpuBar = document.getElementById('cpu-bar'); |
|
|
const ramVal = document.getElementById('ram-val'); |
|
|
const ramBar = document.getElementById('ram-bar'); |
|
|
const pingVal = document.getElementById('ping-val'); |
|
|
const pingBar = document.getElementById('ping-bar'); |
|
|
const jitterVal = document.getElementById('jitter-val'); |
|
|
|
|
|
const hostLight = document.getElementById('host-status-light'); |
|
|
const connLight = document.getElementById('conn-status-light'); |
|
|
|
|
|
const logContainer = document.getElementById('log-container'); |
|
|
const canvas = document.getElementById('trafficChart'); |
|
|
const ctx = canvas.getContext('2d'); |
|
|
|
|
|
|
|
|
resizeCanvas(); |
|
|
window.addEventListener('resize', resizeCanvas); |
|
|
addLog("System initialized. Ready to diagnose.", "info"); |
|
|
|
|
|
|
|
|
|
|
|
function toggleMonitoring(start) { |
|
|
if (start) { |
|
|
if (isRunning) return; |
|
|
isRunning = true; |
|
|
document.getElementById('start-btn').disabled = true; |
|
|
document.getElementById('stop-btn').disabled = false; |
|
|
addLog("Diagnostics started...", "info"); |
|
|
showToast("Monitoring Active", "success"); |
|
|
|
|
|
|
|
|
intervalId = setInterval(updateMetrics, 1000); |
|
|
|
|
|
|
|
|
chartIntervalId = setInterval(updateChartData, 100); |
|
|
} else { |
|
|
isRunning = false; |
|
|
document.getElementById('start-btn').disabled = false; |
|
|
document.getElementById('stop-btn').disabled = true; |
|
|
clearInterval(intervalId); |
|
|
clearInterval(chartIntervalId); |
|
|
addLog("Diagnostics paused by user.", "warn"); |
|
|
showToast("Monitoring Paused", "default"); |
|
|
|
|
|
|
|
|
hostLight.className = "status-indicator"; |
|
|
connLight.className = "status-indicator"; |
|
|
} |
|
|
} |
|
|
|
|
|
function updateMetrics() { |
|
|
|
|
|
|
|
|
let cpu = Math.floor(Math.random() * 30) + 20; |
|
|
let ram = (Math.random() * 2 + 4).toFixed(1); |
|
|
|
|
|
|
|
|
if (Math.random() > 0.8) cpu += 30; |
|
|
|
|
|
|
|
|
cpuVal.innerText = cpu + "%"; |
|
|
cpuBar.style.width = cpu + "%"; |
|
|
|
|
|
if (cpu > 90) { |
|
|
cpuBar.style.backgroundColor = "var(--accent-red)"; |
|
|
hostLight.className = "status-indicator critical"; |
|
|
if(Math.random() > 0.7) addLog("Host CPU Limit Critical! Throttling detected.", "err"); |
|
|
} else if (cpu > 70) { |
|
|
cpuBar.style.backgroundColor = "var(--accent-orange)"; |
|
|
hostLight.className = "status-indicator warning"; |
|
|
} else { |
|
|
cpuBar.style.backgroundColor = "var(--accent-cyan)"; |
|
|
hostLight.className = "status-indicator active"; |
|
|
} |
|
|
|
|
|
|
|
|
ramVal.innerHTML = ram + '<span class="metric-unit">GB</span>'; |
|
|
const ramPercent = (ram / 16) * 100; |
|
|
ramBar.style.width = ramPercent + "%"; |
|
|
if(ramPercent > 80) ramBar.style.backgroundColor = "var(--accent-red)"; |
|
|
else ramBar.style.backgroundColor = "var(--accent-green)"; |
|
|
|
|
|
|
|
|
let ping = Math.floor(Math.random() * 40) + 10; |
|
|
let jitter = Math.floor(Math.random() * 10); |
|
|
|
|
|
|
|
|
if (Math.random() > 0.85) ping += 150; |
|
|
|
|
|
|
|
|
pingVal.innerHTML = ping + '<span class="metric-unit">ms</span>'; |
|
|
jitterVal.innerText = jitter; |
|
|
|
|
|
|
|
|
const pingPercent = Math.min((ping / 200) * 100, 100); |
|
|
pingBar.style.width = pingPercent + "%"; |
|
|
|
|
|
if (ping > 150) { |
|
|
pingBar.style.backgroundColor = "var(--accent-red)"; |
|
|
connLight.className = "status-indicator critical"; |
|
|
if(Math.random() > 0.7) addLog(`Connection timeout: ${ping}ms latency.`, "err"); |
|
|
} else if (ping > 80) { |
|
|
pingBar.style.backgroundColor = "var(--accent-orange)"; |
|
|
connLight.className = "status-indicator warning"; |
|
|
} else { |
|
|
pingBar.style.backgroundColor = "var(--accent-green)"; |
|
|
connLight.className = "status-indicator active"; |
|
|
} |
|
|
} |
|
|
|
|
|
function updateChartData() { |
|
|
|
|
|
trafficData.shift(); |
|
|
errorData.shift(); |
|
|
|
|
|
|
|
|
|
|
|
let newTraffic = Math.floor(Math.random() * 50) + 20; |
|
|
let newError = Math.random() > 0.95 ? Math.floor(Math.random() * 40) : 0; |
|
|
|
|
|
trafficData.push(newTraffic); |
|
|
errorData.push(newError); |
|
|
|
|
|
drawChart(); |
|
|
} |
|
|
|
|
|
|
|
|
function drawChart() { |
|
|
const w = canvas.width; |
|
|
const h = canvas.height; |
|
|
|
|
|
|
|
|
ctx.clearRect(0, 0, w, h); |
|
|
|
|
|
|
|
|
ctx.strokeStyle = "rgba(148, 163, 184, 0.1)"; |
|
|
ctx.lineWidth = 1; |
|
|
ctx.beginPath(); |
|
|
for(let i=0; i<h; i+=40) { |
|
|
ctx.moveTo(0, i); |
|
|
ctx.lineTo(w, i); |
|
|
} |
|
|
ctx.stroke(); |
|
|
|
|
|
|
|
|
drawLine(trafficData, "#06b6d4", 2); |
|
|
|
|
|
|
|
|
drawLine(errorData, "#ef4444", 2); |
|
|
} |
|
|
|
|
|
function drawLine(data, color, width) { |
|
|
const w = canvas.width; |
|
|
const h = canvas.height; |
|
|
const step = w / (maxDataPoints - 1); |
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.strokeStyle = color; |
|
|
ctx.lineWidth = width; |
|
|
ctx.lineJoin = 'round'; |
|
|
|
|
|
for (let i = 0; i < data.length; i++) { |
|
|
|
|
|
|
|
|
const y = h - ((data[i] / 100) * h); |
|
|
const x = i * step; |
|
|
|
|
|
if (i === 0) ctx.moveTo(x, y); |
|
|
else ctx.lineTo(x, y); |
|
|
} |
|
|
ctx.stroke(); |
|
|
|
|
|
|
|
|
ctx.lineTo(w, h); |
|
|
ctx.lineTo(0, h); |
|
|
ctx.closePath(); |
|
|
|
|
|
const gradient = ctx.createLinearGradient(0, 0, 0, h); |
|
|
gradient.addColorStop(0, color + "44"); |
|
|
gradient.addColorStop(1, color + "00"); |
|
|
ctx.fillStyle = gradient; |
|
|
ctx.fill(); |
|
|
} |
|
|
|
|
|
function resizeCanvas() { |
|
|
|
|
|
const container = canvas.parentElement; |
|
|
canvas.width = container.clientWidth; |
|
|
canvas.height = container.clientHeight; |
|
|
drawChart(); |
|
|
} |
|
|
|
|
|
|
|
|
function simulateSpike() { |
|
|
if(!isRunning) { |
|
|
showToast("Start monitoring first!", "warn"); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
cpuVal.innerText = "98%"; |
|
|
cpuBar.style.width = "98%"; |
|
|
cpuBar.style.backgroundColor = "var(--accent-red)"; |
|
|
hostLight.className = "status-indicator critical"; |
|
|
|
|
|
addLog("MANUAL TEST: Simulating Host Limit Breach...", "err"); |
|
|
showToast("Host Limit Test Triggered", "error"); |
|
|
|
|
|
|
|
|
for(let i=0; i<20; i++) { |
|
|
trafficData.push(Math.random() * 20 + 80); |
|
|
trafficData.shift(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function addLog(msg, type) { |
|
|
const time = new Date().toLocaleTimeString('en-US', { hour12: false }); |
|
|
const div = document.createElement('div'); |
|
|
div.className = 'log-entry'; |
|
|
|
|
|
let colorClass = "log-msg-info"; |
|
|
if (type === "warn") colorClass = "log-msg-warn"; |
|
|
if (type === "err") colorClass = "log-msg-err"; |
|
|
|
|
|
div.innerHTML = `<span class="log-time">[${time}]</span> <span class="${colorClass}">${msg}</span>`; |
|
|
|
|
|
logContainer.appendChild(div); |
|
|
logContainer.scrollTop = logContainer.scrollHeight; |
|
|
} |
|
|
|
|
|
function clearLogs() { |
|
|
logContainer.innerHTML = ''; |
|
|
addLog("Logs cleared.", "info"); |
|
|
} |
|
|
|
|
|
function showToast(message, type = "default") { |
|
|
const container = document.getElementById('toast-container'); |
|
|
const toast = document.createElement('div'); |
|
|
toast.className = 'toast'; |
|
|
|
|
|
let icon = '<i class="fa-solid fa-info-circle"></i>'; |
|
|
let color = 'var(--accent-cyan)'; |
|
|
|
|
|
if (type === 'success') { |
|
|
icon = '<i class="fa-solid fa-check-circle"></i>'; |
|
|
color = 'var(--accent-green)'; |
|
|
} else if (type === 'error') { |
|
|
icon = '<i class="fa-solid fa-triangle-exclamation"></i>'; |
|
|
color = 'var(--accent-red)'; |
|
|
} else if (type === 'warn') { |
|
|
icon = '<i class="fa-solid fa-exclamation-circle"></i>'; |
|
|
color = 'var(--accent-orange)'; |
|
|
} |
|
|
|
|
|
toast.style.borderLeftColor = color; |
|
|
toast.innerHTML = `<span style="color:${color}; font-size: 1.2rem;">${icon}</span> ${message}`; |
|
|
|
|
|
container.appendChild(toast); |
|
|
|
|
|
|
|
|
requestAnimationFrame(() => { |
|
|
toast.classList.add('show'); |
|
|
}); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
toast.classList.remove('show'); |
|
|
setTimeout(() => { |
|
|
toast.remove(); |
|
|
}, 300); |
|
|
}, 3000); |
|
|
} |
|
|
|
|
|
</script> |
|
|
</body> |
|
|
</html> |