refactor: status indicator and page

add transition animation to status indicator icon
refactor icon and text to be one element
add Unknown and Loading status
remove sticky class from header
This commit is contained in:
Kentai Radiquum 2024-06-22 14:27:05 +05:00
parent 9b9886a8d2
commit 62644e4c6f
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
4 changed files with 96 additions and 146 deletions

View file

@ -36,20 +36,17 @@
</head>
<body class="light dark:bg-slate-900" id="body">
<header class="sticky top-0 left-0 pt-4 pb-6 shadow-lg bg-slate-50 dark:bg-slate-800">
<header class="top-0 left-0 pt-4 pb-6 shadow-lg bg-slate-50 dark:bg-slate-800">
<div
class="flex flex-col md:flex-row gap-2 md:gap-0 items-center container max-w-[1440px] justify-between px-4">
<div class="self-start"><img src="/public/images/logo-light.svg" alt="wah.su" id="logo" /></div>
<div class="self-start md:self-auto">
<!--noformat-->
<a href="https://status.wah.su" class="flex flex-row items-center gap-2" target="_blank">
<div class="hidden w-4 h-4 bg-green-500 rounded-full dark:bg-green-400" id="status-up-icon"></div>
<div class="hidden w-4 h-4 bg-yellow-400 rounded-full dark:bg-yellow-200" id="status-degraded-icon">
</div>
<div class="hidden w-4 h-4 bg-red-600 rounded-full dark:bg-red-500" id="status-down-icon"></div>
<p class="hidden dark:text-slate-50" id="status-up-text">All Systems Operational.</p>
<p class="hidden dark:text-slate-50" id="status-degraded-text">Degraded Services.</p>
<p class="hidden dark:text-slate-50" id="status-down-text">All Systems Down.</p>
<div class="w-4 h-4 transition ease-in bg-gray-500 rounded-full duration-400" id="status-icon"></div>
<p class="dark:text-slate-50" id="status-text">Fetching Services Status</p>
</a>
<!--noformat-->
</div>
<div class="flex flex-row items-center self-start justify-center gap-6 -ml-4">
<label class="inline-flex items-center cursor-pointer">

View file

@ -1,63 +1,85 @@
const statusIcon = document.getElementById("status-icon");
const statusText = document.getElementById("status-text");
const serviceUp = {
icon: document.getElementById("status-up-icon"),
text: document.getElementById("status-up-text"),
color: ["bg-green-500", "dark:bg-green-400"],
text: "All Services Operational",
};
const serviceDegraded = {
icon: document.getElementById("status-degraded-icon"),
text: document.getElementById("status-degraded-text"),
color: ["bg-yellow-400", "dark:bg-yellow-200"],
text: "Degraded Services",
};
const serviceDown = {
icon: document.getElementById("status-down-icon"),
text: document.getElementById("status-down-text"),
color: ["bg-red-600", "dark:bg-red-500"],
text: "All Services Down",
};
const serviceUnknown = {
color: ["bg-gray-500", "dark:bg-gray-400"],
text: "Services Status Unknown",
};
async function getServicesHealth() {
const serviceStatus = await fetch(
"https://status.wah.su/api/status-page/heartbeat/services"
);
const services = await serviceStatus.json();
const heartbeatDict = services.heartbeatList;
let lastHeartbeats = [];
for (const [key, value] of Object.entries(heartbeatDict)) {
lastHeartbeats.push(
heartbeatDict[key][heartbeatDict[key].length - 1].status
try {
const serviceStatus = await fetch(
"https://status.wah.su/api/status-page/heartbeat/services"
);
}
let status = "up";
const count = lastHeartbeats.reduce((partialSum, a) => partialSum + a, 0);
const services = await serviceStatus.json();
const heartbeatDict = services.heartbeatList;
let lastHeartbeats = [];
if (count === lastHeartbeats.length) {
status = "up";
} else if (count === 0) {
status = "down";
} else {
status = "degraded";
}
for (const [key, value] of Object.entries(heartbeatDict)) {
lastHeartbeats.push(
heartbeatDict[key][heartbeatDict[key].length - 1].status
);
}
if (status === "up") {
serviceUp.icon.classList.remove("hidden");
serviceUp.text.classList.remove("hidden");
serviceDegraded.icon.classList.add("hidden");
serviceDegraded.text.classList.add("hidden");
serviceDown.icon.classList.add("hidden");
serviceDown.text.classList.add("hidden");
} else if (status === "degraded") {
serviceUp.icon.classList.add("hidden");
serviceUp.text.classList.add("hidden");
serviceDegraded.icon.classList.remove("hidden");
serviceDegraded.text.classList.remove("hidden");
serviceDown.icon.classList.add("hidden");
serviceDown.text.classList.add("hidden");
} else if (status === "down") {
serviceUp.icon.classList.add("hidden");
serviceUp.text.classList.add("hidden");
serviceDegraded.icon.classList.add("hidden");
serviceDegraded.text.classList.add("hidden");
serviceDown.icon.classList.remove("hidden");
serviceDown.text.classList.remove("hidden");
let status = "up";
const count = lastHeartbeats.reduce((partialSum, a) => partialSum + a, 0);
if (count === lastHeartbeats.length) {
status = "up";
} else if (count === 0) {
status = "down";
} else {
status = "degraded";
}
if (status === "up") {
statusIcon.classList.add(...serviceUp.color);
statusIcon.classList.remove(
...serviceDegraded.color,
...serviceDown.color,
...serviceUnknown.color
);
statusText.textContent = serviceUp.text;
} else if (status === "degraded") {
statusIcon.classList.add(...serviceDegraded.color);
statusIcon.classList.remove(
...serviceUp.color,
...serviceDown.color,
...serviceUnknown.color
);
statusText.textContent = serviceDegraded.text;
} else if (status === "down") {
statusIcon.classList.add(...serviceDown.color);
statusIcon.classList.remove(
...serviceUp.color,
...serviceDegraded.color,
...serviceUnknown.color
);
statusText.textContent = serviceDown.text;
}
} catch (error) {
statusIcon.classList.add(...serviceUnknown.color);
statusIcon.classList.remove(
...serviceUp.color,
...serviceDegraded.color,
...serviceDown.color
);
statusText.textContent = serviceUnknown.text;
console.log("Failed to fetch services status: " + error);
return;
}
}

View file

@ -1093,10 +1093,6 @@ input:checked + .toggle-bg {
position: relative;
}
.sticky {
position: sticky;
}
.inset-0 {
inset: 0px;
}
@ -1141,31 +1137,15 @@ input:checked + .toggle-bg {
z-index: 50;
}
.col-span-2 {
grid-column: span 2 / span 2;
}
.col-span-3 {
grid-column: span 3 / span 3;
}
.col-span-1 {
grid-column: span 1 / span 1;
}
.row-span-1 {
grid-row: span 1 / span 1;
}
.row-span-2 {
grid-row: span 2 / span 2;
}
.mx-auto {
margin-left: auto;
margin-right: auto;
}
.-ml-4 {
margin-left: -1rem;
}
.mb-1 {
margin-bottom: 0.25rem;
}
@ -1186,8 +1166,8 @@ input:checked + .toggle-bg {
margin-inline-end: 0.5rem;
}
.ml-8 {
margin-left: 2rem;
.ml-2 {
margin-left: 0.5rem;
}
.mr-4 {
@ -1214,18 +1194,6 @@ input:checked + .toggle-bg {
margin-top: 1.5rem;
}
.ml-2 {
margin-left: 0.5rem;
}
.ml-4 {
margin-left: 1rem;
}
.-ml-4 {
margin-left: -1rem;
}
.block {
display: block;
}
@ -1396,10 +1364,6 @@ input:checked + .toggle-bg {
grid-template-columns: repeat(7, minmax(0, 1fr));
}
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.flex-row {
flex-direction: row;
}
@ -1452,14 +1416,6 @@ input:checked + .toggle-bg {
gap: 1.5rem;
}
.gap-4 {
gap: 1rem;
}
.gap-8 {
gap: 2rem;
}
.space-x-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(0.5rem * var(--tw-space-x-reverse));
@ -1555,6 +1511,11 @@ input:checked + .toggle-bg {
background-color: rgb(229 231 235 / var(--tw-bg-opacity));
}
.bg-gray-500 {
--tw-bg-opacity: 1;
background-color: rgb(107 114 128 / var(--tw-bg-opacity));
}
.bg-gray-800 {
--tw-bg-opacity: 1;
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
@ -1653,21 +1614,6 @@ input:checked + .toggle-bg {
padding-bottom: 1rem;
}
.px-2\.5 {
padding-left: 0.625rem;
padding-right: 0.625rem;
}
.py-1 {
padding-top: 0.25rem;
padding-bottom: 0.25rem;
}
.py-1\.5 {
padding-top: 0.375rem;
padding-bottom: 0.375rem;
}
.pb-6 {
padding-bottom: 1.5rem;
}
@ -1824,6 +1770,10 @@ input:checked + .toggle-bg {
transition-duration: 150ms;
}
.ease-in {
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
}
.ease-out {
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
@ -2000,36 +1950,11 @@ input:checked + .toggle-bg {
--tw-ring-color: rgb(164 202 254 / var(--tw-ring-opacity));
}
@media (min-width: 640px) {
.sm\:block {
display: block;
}
.sm\:px-5 {
padding-left: 1.25rem;
padding-right: 1.25rem;
}
.sm\:py-2 {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
.sm\:py-2\.5 {
padding-top: 0.625rem;
padding-bottom: 0.625rem;
}
}
@media (min-width: 768px) {
.md\:ml-0 {
margin-left: 0px;
}
.md\:flex {
display: flex;
}
.md\:flex-row {
flex-direction: row;
}
@ -2101,6 +2026,11 @@ input:checked + .toggle-bg {
background-color: rgb(28 100 242 / var(--tw-bg-opacity));
}
.dark\:bg-gray-400:where(.dark, .dark *) {
--tw-bg-opacity: 1;
background-color: rgb(156 163 175 / var(--tw-bg-opacity));
}
.dark\:bg-gray-600:where(.dark, .dark *) {
--tw-bg-opacity: 1;
background-color: rgb(75 85 99 / var(--tw-bg-opacity));

View file

@ -5,6 +5,7 @@ module.exports = {
"./index.html",
"./src/**/*.{html,js}",
"./public/js/cards.js",
"./public/js/status.js",
"./node_modules/flowbite/**/*.js",
],
theme: {