mirror of
https://github.com/asimonson1125/asimonson1125.github.io.git
synced 2026-02-25 05:09:49 -06:00
productionalizing?
This commit is contained in:
@@ -3,7 +3,7 @@ from flask_minify import Minify
|
||||
import json
|
||||
import werkzeug.exceptions as HTTPerror
|
||||
from config import *
|
||||
from monitor import monitor
|
||||
from monitor import monitor, SERVICES
|
||||
|
||||
app = flask.Flask(__name__)
|
||||
|
||||
@@ -43,6 +43,7 @@ pages['projects']['skillList'] = skillList
|
||||
pages['projects']['projects'] = proj
|
||||
pages['home']['books'] = books
|
||||
pages['books']['books'] = books
|
||||
pages['status']['services'] = SERVICES
|
||||
|
||||
@app.route('/api/status')
|
||||
def api_status():
|
||||
|
||||
@@ -30,15 +30,9 @@ SERVICES = [
|
||||
'timeout': 10
|
||||
},
|
||||
{
|
||||
'id': 'pass',
|
||||
'name': 'pass.asimonson.com',
|
||||
'url': 'https://pass.asimonson.com',
|
||||
'timeout': 10
|
||||
},
|
||||
{
|
||||
'id': 'ssh',
|
||||
'name': 'ssh.asimonson.com',
|
||||
'url': 'https://ssh.asimonson.com',
|
||||
'id': 'balls',
|
||||
'name': 'balls.asimonson.com',
|
||||
'url': 'https://balls.asimonson.com',
|
||||
'timeout': 10
|
||||
}
|
||||
]
|
||||
@@ -182,8 +176,22 @@ class ServiceMonitor:
|
||||
if datetime.fromisoformat(c['timestamp']) > cutoff
|
||||
]
|
||||
|
||||
if not checks:
|
||||
return None
|
||||
if not checks:
|
||||
return None
|
||||
|
||||
# Require minimum data coverage for the time period
|
||||
# Calculate expected number of checks for this period
|
||||
expected_checks = (hours * 3600) / CHECK_INTERVAL
|
||||
|
||||
# Require at least 50% of expected checks to show this metric
|
||||
minimum_checks = max(3, expected_checks * 0.5)
|
||||
|
||||
if len(checks) < minimum_checks:
|
||||
return None
|
||||
else:
|
||||
# For all-time, require at least 3 checks
|
||||
if len(checks) < 3:
|
||||
return None
|
||||
|
||||
online_count = sum(1 for c in checks if c['status'] == 'online')
|
||||
uptime = (online_count / len(checks)) * 100
|
||||
|
||||
@@ -104,11 +104,30 @@ strong {
|
||||
color: #ecebeb;
|
||||
}
|
||||
|
||||
p, li {
|
||||
ul {
|
||||
margin: 0;
|
||||
padding-left: 1.5em;
|
||||
color: #a8a8a8;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.5em;
|
||||
color: #a8a8a8;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: #ecebeb;
|
||||
}
|
||||
|
||||
p, li, span {
|
||||
color: rgb(212, 212, 212);
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
||||
a, a p {
|
||||
color: #a0a0a0a0;
|
||||
text-decoration: none;
|
||||
@@ -1297,20 +1316,116 @@ tr {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.status-info {
|
||||
/* Overall Status Bar */
|
||||
/* Overall Status Bar */
|
||||
.overall-status-bar {
|
||||
background: rgba(24, 24, 24, 0.95);
|
||||
border-radius: 0.5em;
|
||||
padding: 2em;
|
||||
margin-bottom: 2em;
|
||||
border-top: solid 4px rgba(139, 36, 36, 0.5);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
|
||||
transition: border-color 0.5s ease;
|
||||
}
|
||||
|
||||
.overall-status-bar.all-operational {
|
||||
border-top-color: rgba(76, 175, 80, 0.8);
|
||||
}
|
||||
|
||||
.overall-status-bar.partial-outage {
|
||||
border-top-color: rgba(255, 193, 7, 0.8);
|
||||
}
|
||||
|
||||
.overall-status-bar.major-outage {
|
||||
border-top-color: rgba(244, 67, 54, 0.8);
|
||||
}
|
||||
|
||||
.overall-status-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 2em;
|
||||
padding: 1em;
|
||||
background: rgba(24, 24, 24, 0.85);
|
||||
border-radius: 0.5em;
|
||||
border: solid 2px rgba(139, 36, 36, 0.5);
|
||||
flex-wrap: wrap;
|
||||
gap: 2em;
|
||||
}
|
||||
|
||||
.status-info span {
|
||||
.overall-status-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1.5em;
|
||||
}
|
||||
|
||||
.overall-status-icon {
|
||||
font-size: 3rem;
|
||||
line-height: 1;
|
||||
animation: spin 2s linear infinite;
|
||||
}
|
||||
|
||||
.overall-status-icon.operational {
|
||||
color: #4caf50;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
.overall-status-icon.partial {
|
||||
color: #ffc107;
|
||||
animation: pulse-icon 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.overall-status-icon.major {
|
||||
color: #f44336;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes pulse-icon {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
.overall-status-title {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
color: #ecebeb;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.overall-status-subtitle {
|
||||
margin: 0.3em 0 0 0;
|
||||
font-size: 1rem;
|
||||
color: #a8a8a8;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.overall-status-metrics {
|
||||
display: flex;
|
||||
gap: 2em;
|
||||
}
|
||||
|
||||
.metric-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 1em 1.5em;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 0.5em;
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.metric-number {
|
||||
font-size: 2rem;
|
||||
font-weight: bold;
|
||||
color: #ecebeb;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.metric-label {
|
||||
font-size: 0.85rem;
|
||||
color: #a8a8a8;
|
||||
margin-top: 0.3em;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
#refreshBtn {
|
||||
@@ -1504,35 +1619,28 @@ tr {
|
||||
}
|
||||
|
||||
.uptime-values strong {
|
||||
color: #4caf50;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.status-info-box {
|
||||
background: rgba(24, 24, 24, 0.85);
|
||||
border-radius: 0.5em;
|
||||
padding: 1.5em;
|
||||
border: solid 2px rgba(139, 36, 36, 0.5);
|
||||
margin-top: 2em;
|
||||
/* Uptime color coding based on percentage */
|
||||
.uptime-excellent {
|
||||
color: #4caf50 !important; /* 99%+ - Green */
|
||||
}
|
||||
|
||||
.status-info-box h4 {
|
||||
margin-top: 0;
|
||||
color: #ecebeb;
|
||||
.uptime-good {
|
||||
color: #8bc34a !important; /* 95-99% - Light green */
|
||||
}
|
||||
|
||||
.status-info-box ul {
|
||||
margin: 0;
|
||||
padding-left: 1.5em;
|
||||
color: #a8a8a8;
|
||||
.uptime-fair {
|
||||
color: #ffc107 !important; /* 90-95% - Yellow */
|
||||
}
|
||||
|
||||
.status-info-box li {
|
||||
margin-bottom: 0.5em;
|
||||
color: #a8a8a8;
|
||||
.uptime-poor {
|
||||
color: #f44336 !important; /* <90% - Red */
|
||||
}
|
||||
|
||||
.status-info-box strong {
|
||||
color: #ecebeb;
|
||||
.uptime-none {
|
||||
color: #888 !important; /* No data - Gray */
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1400px) {
|
||||
@@ -1549,4 +1657,19 @@ tr {
|
||||
flex-direction: column;
|
||||
gap: 0.5em;
|
||||
}
|
||||
|
||||
.overall-status-content {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.overall-status-indicator {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.overall-status-metrics {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,9 @@ function updateStatusDisplay(data) {
|
||||
updateServiceCard(service);
|
||||
});
|
||||
|
||||
// Update overall status
|
||||
updateOverallStatus(data.services);
|
||||
|
||||
// Re-enable refresh button
|
||||
const refreshBtn = document.getElementById('refreshBtn');
|
||||
if (refreshBtn) {
|
||||
@@ -109,24 +112,29 @@ function updateServiceCard(service) {
|
||||
if (uptimeDisplay && service.uptime) {
|
||||
const uptimeHTML = [];
|
||||
|
||||
if (service.uptime['24h'] !== null) {
|
||||
uptimeHTML.push(`24h: <strong>${service.uptime['24h']}%</strong>`);
|
||||
}
|
||||
if (service.uptime['7d'] !== null) {
|
||||
uptimeHTML.push(`7d: <strong>${service.uptime['7d']}%</strong>`);
|
||||
}
|
||||
if (service.uptime['30d'] !== null) {
|
||||
uptimeHTML.push(`30d: <strong>${service.uptime['30d']}%</strong>`);
|
||||
}
|
||||
if (service.uptime.all_time !== null) {
|
||||
uptimeHTML.push(`All: <strong>${service.uptime.all_time}%</strong>`);
|
||||
}
|
||||
// Helper function to get color class based on uptime percentage
|
||||
const getUptimeClass = (value) => {
|
||||
if (value === null) return 'uptime-none';
|
||||
if (value >= 99) return 'uptime-excellent';
|
||||
if (value >= 95) return 'uptime-good';
|
||||
if (value >= 90) return 'uptime-fair';
|
||||
return 'uptime-poor';
|
||||
};
|
||||
|
||||
if (uptimeHTML.length > 0) {
|
||||
uptimeDisplay.innerHTML = uptimeHTML.join(' | ');
|
||||
} else {
|
||||
uptimeDisplay.textContent = 'No data yet';
|
||||
}
|
||||
// Helper function to format uptime value
|
||||
const formatUptime = (value, label) => {
|
||||
const display = value !== null ? `${value}%` : '--';
|
||||
const colorClass = getUptimeClass(value);
|
||||
return `${label}: <strong class="${colorClass}">${display}</strong>`;
|
||||
};
|
||||
|
||||
// Add all uptime metrics
|
||||
uptimeHTML.push(formatUptime(service.uptime['24h'], '24h'));
|
||||
uptimeHTML.push(formatUptime(service.uptime['7d'], '7d'));
|
||||
uptimeHTML.push(formatUptime(service.uptime['30d'], '30d'));
|
||||
uptimeHTML.push(formatUptime(service.uptime.all_time, 'All'));
|
||||
|
||||
uptimeDisplay.innerHTML = uptimeHTML.join(' | ');
|
||||
}
|
||||
|
||||
// Update total checks
|
||||
@@ -135,6 +143,68 @@ function updateServiceCard(service) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update overall status bar
|
||||
*/
|
||||
function updateOverallStatus(services) {
|
||||
const overallBar = document.getElementById('overallStatus');
|
||||
const icon = overallBar.querySelector('.overall-status-icon');
|
||||
const title = overallBar.querySelector('.overall-status-title');
|
||||
const subtitle = overallBar.querySelector('.overall-status-subtitle');
|
||||
const onlineCount = document.getElementById('onlineCount');
|
||||
const totalCount = document.getElementById('totalCount');
|
||||
|
||||
// Count service statuses
|
||||
const total = services.length;
|
||||
const online = services.filter(s => s.status === 'online').length;
|
||||
const degraded = services.filter(s => s.status === 'degraded' || s.status === 'timeout').length;
|
||||
const offline = services.filter(s => s.status === 'offline').length;
|
||||
|
||||
// Update counts
|
||||
onlineCount.textContent = online;
|
||||
totalCount.textContent = total;
|
||||
|
||||
// Remove all status classes
|
||||
overallBar.classList.remove('all-operational', 'partial-outage', 'major-outage');
|
||||
icon.classList.remove('operational', 'partial', 'major', 'loading');
|
||||
|
||||
// Determine overall status
|
||||
if (online === total) {
|
||||
// All systems operational
|
||||
overallBar.classList.add('all-operational');
|
||||
icon.classList.add('operational');
|
||||
icon.textContent = '✓';
|
||||
title.textContent = 'All Systems Operational';
|
||||
subtitle.textContent = `All ${total} services are running normally`;
|
||||
} else if (offline >= Math.ceil(total / 2)) {
|
||||
// Major outage (50% or more offline)
|
||||
overallBar.classList.add('major-outage');
|
||||
icon.classList.add('major');
|
||||
icon.textContent = '✕';
|
||||
title.textContent = 'Major Outage';
|
||||
subtitle.textContent = `${offline} service${offline !== 1 ? 's' : ''} offline, ${degraded} degraded`;
|
||||
} else if (offline > 0 || degraded > 0) {
|
||||
// Partial outage
|
||||
overallBar.classList.add('partial-outage');
|
||||
icon.classList.add('partial');
|
||||
icon.textContent = '⚠';
|
||||
title.textContent = 'Partial Outage';
|
||||
if (offline > 0 && degraded > 0) {
|
||||
subtitle.textContent = `${offline} offline, ${degraded} degraded`;
|
||||
} else if (offline > 0) {
|
||||
subtitle.textContent = `${offline} service${offline !== 1 ? 's' : ''} offline`;
|
||||
} else {
|
||||
subtitle.textContent = `${degraded} service${degraded !== 1 ? 's' : ''} degraded`;
|
||||
}
|
||||
} else {
|
||||
// Unknown state
|
||||
icon.classList.add('loading');
|
||||
icon.textContent = '◐';
|
||||
title.textContent = 'Status Unknown';
|
||||
subtitle.textContent = 'Waiting for service data';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show error message
|
||||
*/
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
{
|
||||
"last_check": "2026-02-11T14:53:09.045018",
|
||||
"services": {
|
||||
"main": {
|
||||
"name": "asimonson.com",
|
||||
"url": "https://asimonson.com",
|
||||
"status": "online",
|
||||
"response_time": 170,
|
||||
"status_code": 200,
|
||||
"last_online": "2026-02-11T14:53:08.089141",
|
||||
"checks": [
|
||||
{
|
||||
"timestamp": "2026-02-11T14:45:35.008804",
|
||||
"status": "online",
|
||||
"response_time": 171,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:51:02.673733",
|
||||
"status": "online",
|
||||
"response_time": 138,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:53:08.089141",
|
||||
"status": "online",
|
||||
"response_time": 170,
|
||||
"status_code": 200
|
||||
}
|
||||
]
|
||||
},
|
||||
"files": {
|
||||
"name": "files.asimonson.com",
|
||||
"url": "https://files.asimonson.com",
|
||||
"status": "online",
|
||||
"response_time": 215,
|
||||
"status_code": 200,
|
||||
"last_online": "2026-02-11T14:53:08.259522",
|
||||
"checks": [
|
||||
{
|
||||
"timestamp": "2026-02-11T14:45:35.180195",
|
||||
"status": "online",
|
||||
"response_time": 285,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:51:02.812769",
|
||||
"status": "online",
|
||||
"response_time": 259,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:53:08.259522",
|
||||
"status": "online",
|
||||
"response_time": 215,
|
||||
"status_code": 200
|
||||
}
|
||||
]
|
||||
},
|
||||
"git": {
|
||||
"name": "git.asimonson.com",
|
||||
"url": "https://git.asimonson.com",
|
||||
"status": "online",
|
||||
"response_time": 145,
|
||||
"status_code": 200,
|
||||
"last_online": "2026-02-11T14:53:08.475376",
|
||||
"checks": [
|
||||
{
|
||||
"timestamp": "2026-02-11T14:45:35.465748",
|
||||
"status": "online",
|
||||
"response_time": 297,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:51:03.072293",
|
||||
"status": "online",
|
||||
"response_time": 293,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:53:08.475376",
|
||||
"status": "online",
|
||||
"response_time": 145,
|
||||
"status_code": 200
|
||||
}
|
||||
]
|
||||
},
|
||||
"pass": {
|
||||
"name": "pass.asimonson.com",
|
||||
"url": "https://pass.asimonson.com",
|
||||
"status": "online",
|
||||
"response_time": 160,
|
||||
"status_code": 200,
|
||||
"last_online": "2026-02-11T14:53:08.621016",
|
||||
"checks": [
|
||||
{
|
||||
"timestamp": "2026-02-11T14:45:35.763775",
|
||||
"status": "online",
|
||||
"response_time": 253,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:51:03.365544",
|
||||
"status": "online",
|
||||
"response_time": 228,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:53:08.621016",
|
||||
"status": "online",
|
||||
"response_time": 160,
|
||||
"status_code": 200
|
||||
}
|
||||
]
|
||||
},
|
||||
"ssh": {
|
||||
"name": "ssh.asimonson.com",
|
||||
"url": "https://ssh.asimonson.com",
|
||||
"status": "online",
|
||||
"response_time": 263,
|
||||
"status_code": 200,
|
||||
"last_online": "2026-02-11T14:53:08.781704",
|
||||
"checks": [
|
||||
{
|
||||
"timestamp": "2026-02-11T14:45:36.017180",
|
||||
"status": "online",
|
||||
"response_time": 378,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:51:03.594307",
|
||||
"status": "online",
|
||||
"response_time": 411,
|
||||
"status_code": 200
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-02-11T14:53:08.781704",
|
||||
"status": "online",
|
||||
"response_time": 263,
|
||||
"status_code": 200
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,160 +2,18 @@
|
||||
<div class="foreground"></div>
|
||||
<div class="foregroundContent">
|
||||
<h2 class='concentratedHead'>Service Status Monitor</h2>
|
||||
<p class="status-subtitle">Automated monitoring of asimonson.com services</p>
|
||||
|
||||
<div class="status-info">
|
||||
<div>
|
||||
<span id="lastUpdate">Last checked: Loading...</span>
|
||||
<br>
|
||||
<span id="nextUpdate" style="font-size: 0.85em; color: #888;">Next check: --</span>
|
||||
</div>
|
||||
<button id="refreshBtn" onclick="refreshStatus()">Refresh Now</button>
|
||||
</div>
|
||||
|
||||
<div class="status-container">
|
||||
<div class="status-card" id="status-main">
|
||||
<div class="status-header">
|
||||
<h3>asimonson.com</h3>
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot loading"></span>
|
||||
<span class="status-text">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-details">
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Response Time:</span>
|
||||
<span class="metric-value" id="time-main">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Status Code:</span>
|
||||
<span class="metric-value" id="code-main">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Total Checks:</span>
|
||||
<span class="metric-value" id="checks-main">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-uptime">
|
||||
<div class="uptime-label">Uptime:</div>
|
||||
<div class="uptime-values" id="uptime-main">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-card" id="status-files">
|
||||
<div class="status-header">
|
||||
<h3>files.asimonson.com</h3>
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot loading"></span>
|
||||
<span class="status-text">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-details">
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Response Time:</span>
|
||||
<span class="metric-value" id="time-files">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Status Code:</span>
|
||||
<span class="metric-value" id="code-files">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Total Checks:</span>
|
||||
<span class="metric-value" id="checks-files">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-uptime">
|
||||
<div class="uptime-label">Uptime:</div>
|
||||
<div class="uptime-values" id="uptime-files">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-card" id="status-git">
|
||||
<div class="status-header">
|
||||
<h3>git.asimonson.com</h3>
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot loading"></span>
|
||||
<span class="status-text">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-details">
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Response Time:</span>
|
||||
<span class="metric-value" id="time-git">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Status Code:</span>
|
||||
<span class="metric-value" id="code-git">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Total Checks:</span>
|
||||
<span class="metric-value" id="checks-git">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-uptime">
|
||||
<div class="uptime-label">Uptime:</div>
|
||||
<div class="uptime-values" id="uptime-git">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-card" id="status-pass">
|
||||
<div class="status-header">
|
||||
<h3>pass.asimonson.com</h3>
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot loading"></span>
|
||||
<span class="status-text">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-details">
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Response Time:</span>
|
||||
<span class="metric-value" id="time-pass">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Status Code:</span>
|
||||
<span class="metric-value" id="code-pass">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Total Checks:</span>
|
||||
<span class="metric-value" id="checks-pass">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-uptime">
|
||||
<div class="uptime-label">Uptime:</div>
|
||||
<div class="uptime-values" id="uptime-pass">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-card" id="status-ssh">
|
||||
<div class="status-header">
|
||||
<h3>ssh.asimonson.com</h3>
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot loading"></span>
|
||||
<span class="status-text">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-details">
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Response Time:</span>
|
||||
<span class="metric-value" id="time-ssh">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Status Code:</span>
|
||||
<span class="metric-value" id="code-ssh">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Total Checks:</span>
|
||||
<span class="metric-value" id="checks-ssh">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-uptime">
|
||||
<div class="uptime-label">Uptime:</div>
|
||||
<div class="uptime-values" id="uptime-ssh">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-legend">
|
||||
<div class='flex spaceBetween'>
|
||||
<div>
|
||||
<span id="lastUpdate">Last checked: Loading...</span>
|
||||
<br />
|
||||
<span id="nextUpdate">Next check: --</span>
|
||||
</div>
|
||||
<button id="refreshBtn" onclick="refreshStatus()">Refresh Now</button>
|
||||
</div>
|
||||
<br/>
|
||||
|
||||
<h4>Status Legend</h4>
|
||||
<div class="legend-items">
|
||||
<div class="legend-item">
|
||||
@@ -173,13 +31,67 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-info-box">
|
||||
<!-- Overall Status Bar -->
|
||||
<div class="overall-status-bar" id="overallStatus">
|
||||
<div class="overall-status-content">
|
||||
<div class="overall-status-indicator">
|
||||
<span class="overall-status-icon loading">◐</span>
|
||||
<div>
|
||||
<h3 class="overall-status-title">Checking Systems...</h3>
|
||||
<p class="overall-status-subtitle">Loading service status</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="overall-status-metrics">
|
||||
<div class="metric-box">
|
||||
<span class="metric-number" id="onlineCount">--</span>
|
||||
<span class="metric-label">Online</span>
|
||||
</div>
|
||||
<div class="metric-box">
|
||||
<span class="metric-number" id="totalCount">--</span>
|
||||
<span class="metric-label">Total</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="status-container">
|
||||
{% for service in var.services %}
|
||||
<a href="https://{{ service.url }}">
|
||||
<div class="status-card" id="status-{{ service.id }}">
|
||||
<div class="status-header">
|
||||
<h3>{{ service.name }}</h3>
|
||||
<div class="status-indicator">
|
||||
<span class="status-dot loading"></span>
|
||||
<span class="status-text">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-details">
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Response Time:</span>
|
||||
<span class="metric-value" id="time-{{ service.id }}">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Status Code:</span>
|
||||
<span class="metric-value" id="code-{{ service.id }}">--</span>
|
||||
</div>
|
||||
<div class="status-metric">
|
||||
<span class="metric-label">Total Checks:</span>
|
||||
<span class="metric-value" id="checks-{{ service.id }}">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-uptime">
|
||||
<div class="uptime-label">Uptime:</div>
|
||||
<div class="uptime-values" id="uptime-{{ service.id }}">Loading...</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<div class="status-legend">
|
||||
<h4>About This Monitor</h4>
|
||||
<ul>
|
||||
<li><strong>Check Frequency:</strong> Services are checked automatically every 2 hours from the server</li>
|
||||
<li><strong>Uptime Calculation:</strong> Based on historical check data (24h, 7d, 30d, and all-time)</li>
|
||||
<li><strong>Response Time:</strong> Time taken to receive a response from the service</li>
|
||||
<li><strong>Status Code:</strong> HTTP response code from the service</li>
|
||||
<li><strong>Check Frequency:</strong> Services are checked automatically every 30 minutes from the server</li>
|
||||
<li><strong>Page Refresh:</strong> This page auto-refreshes every 5 minutes to show latest data</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user