mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 13:17:00 +04:00
115 lines
4.0 KiB
Plaintext
115 lines
4.0 KiB
Plaintext
---
|
||
import CaptureScript from '../CaptureScript.astro'
|
||
|
||
interface Props {
|
||
id: string
|
||
services?: string[]
|
||
days?: number
|
||
seed?: number
|
||
class?: string
|
||
}
|
||
|
||
const { id, services = ['API', 'Dashboard', 'Webhooks', 'Email delivery'], days = 60, seed = 18, class: className } = Astro.props
|
||
|
||
const cardId = `system-status-${id}`
|
||
---
|
||
|
||
<div class:list={['card', className]} id={cardId}>
|
||
<div class="card-header">
|
||
<h3 class="card-title">System status</h3>
|
||
<div class="card-actions">
|
||
<span class="status status-green" data-status>
|
||
<span class="status-dot status-dot-animated"></span>
|
||
<span data-status-label>All systems operational</span>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="list-group list-group-flush">
|
||
{
|
||
services.map((service) => (
|
||
<div class="list-group-item">
|
||
<div class="d-flex align-items-baseline mb-2">
|
||
<div class="fw-medium">{service}</div>
|
||
<div class="ms-auto text-secondary">
|
||
<span data-uptime-value>–</span> uptime
|
||
</div>
|
||
</div>
|
||
<div class="tracking" data-uptime={service} />
|
||
</div>
|
||
))
|
||
}
|
||
</div>
|
||
<div class="card-footer">
|
||
<div class="d-flex align-items-center text-secondary">
|
||
<div>{days} days ago</div>
|
||
<div class="legend-list mx-auto">
|
||
<span class="legend legend-green"><span class="legend-dot"></span>Operational</span>
|
||
<span class="legend legend-yellow"><span class="legend-dot"></span>Degraded</span>
|
||
<span class="legend legend-red"><span class="legend-dot"></span>Outage</span>
|
||
</div>
|
||
<div>Today</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<CaptureScript>
|
||
<!-- BEGIN SYSTEM STATUS -->
|
||
<script is:inline define:vars={{ cardId, days, seed }}>
|
||
// Share of days with an outage / degraded performance, and how much a degraded day counts
|
||
const OUTAGE_RATE = 0.02
|
||
const DEGRADED_RATE = 0.04
|
||
const DEGRADED_WEIGHT = 0.5
|
||
|
||
const STATUSES = {
|
||
up: { label: 'Operational', color: 'bg-green' },
|
||
degraded: { label: 'Degraded performance', color: 'bg-yellow' },
|
||
down: { label: 'Outage', color: 'bg-red' },
|
||
}
|
||
|
||
// Mulberry32: tiny seeded PRNG, so every load draws the same history
|
||
function createRandom(seed) {
|
||
return function () {
|
||
seed = (seed + 0x6d2b79f5) | 0
|
||
let t = Math.imul(seed ^ (seed >>> 15), 1 | seed)
|
||
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t
|
||
return ((t ^ (t >>> 14)) >>> 0) / 4294967296
|
||
}
|
||
}
|
||
|
||
function initSystemStatus() {
|
||
const card = document.getElementById(cardId)
|
||
const random = createRandom(seed)
|
||
const today = new Date()
|
||
let allOperational = true
|
||
|
||
card.querySelectorAll('[data-uptime]').forEach((container) => {
|
||
let score = 0
|
||
|
||
for (let i = days - 1; i >= 0; i--) {
|
||
const roll = random()
|
||
const status = roll < OUTAGE_RATE ? 'down' : roll < OUTAGE_RATE + DEGRADED_RATE ? 'degraded' : 'up'
|
||
const date = new Date(today.getFullYear(), today.getMonth(), today.getDate() - i)
|
||
|
||
const bar = document.createElement('div')
|
||
bar.className = 'tracking-block ' + STATUSES[status].color
|
||
bar.title = date.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' }) + ' – ' + STATUSES[status].label
|
||
container.appendChild(bar)
|
||
|
||
score += status === 'up' ? 1 : status === 'degraded' ? DEGRADED_WEIGHT : 0
|
||
}
|
||
|
||
if (score < days) allOperational = false
|
||
|
||
container.parentElement.querySelector('[data-uptime-value]').textContent = ((score / days) * 100).toFixed(2) + '%'
|
||
})
|
||
|
||
if (!allOperational) {
|
||
card.querySelector('[data-status]').classList.replace('status-green', 'status-yellow')
|
||
card.querySelector('[data-status-label]').textContent = 'Some systems affected'
|
||
}
|
||
}
|
||
|
||
document.readyState !== 'loading' ? initSystemStatus() : document.addEventListener('DOMContentLoaded', initSystemStatus, { once: true })
|
||
</script>
|
||
<!-- END SYSTEM STATUS -->
|
||
</CaptureScript>
|