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:
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user