Files
tickte-system/src/lib/serverpulsFormat.js
T
2026-09-30 12:43:13 +00:00

98 lines
3.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Reine Format-Helfer fuer die Serverpuls-Seite (kein React, unter Node testbar).
const nf = (digits) =>
new Intl.NumberFormat('de-DE', { minimumFractionDigits: 0, maximumFractionDigits: digits })
const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
export function formatBytes(n) {
if (n === null || n === undefined || Number.isNaN(Number(n))) return '–'
let v = Math.abs(Number(n))
if (v < 1) return '0 B'
let i = 0
while (v >= 1024 && i < UNITS.length - 1) {
v /= 1024
i += 1
}
const sign = n < 0 ? '−' : ''
return `${sign}${nf(i === 0 ? 0 : 1).format(v)} ${UNITS[i]}`
}
export function formatDelta(pct) {
if (pct === null || pct === undefined || Number.isNaN(Number(pct))) {
return { text: '–', dir: 'flat' }
}
const rounded = Math.round(Number(pct) * 10) / 10
if (rounded === 0) return { text: '0 %', dir: 'flat' }
const sign = rounded > 0 ? '+' : '−'
return { text: `${sign}${nf(1).format(Math.abs(rounded))} %`, dir: rounded > 0 ? 'up' : 'down' }
}
export const STALE_MS = 15 * 60 * 1000
export function ageLabel(ts, now = Date.now()) {
if (ts === null || ts === undefined) return { text: 'keine Messung', stale: true }
const diff = Math.max(0, now - ts)
const min = Math.floor(diff / 60000)
let text
if (min < 1) text = 'gerade eben'
else if (min < 60) text = `vor ${min} Min.`
else if (min < 1440) text = `vor ${Math.floor(min / 60)} Std.`
else text = `vor ${Math.floor(min / 1440)} T.`
return { text, stale: diff > STALE_MS }
}
// RAM: value ist FREIER Speicher, belegt = 1 - frei/gesamt (in Prozent).
export function usedPct(free, total) {
if (free === null || free === undefined || !total) return null
return Math.round((1 - free / total) * 1000) / 10
}
export function formatPct(v, digits = 1) {
if (v === null || v === undefined) return '–'
return `${nf(digits).format(v)} %`
}
export function formatNumber(v, digits = 2) {
if (v === null || v === undefined) return '–'
return nf(digits).format(v)
}
// --- Zeitachsen (Europe/Berlin, de-DE) ---
const TZ = 'Europe/Berlin'
const dtf = (opts) => new Intl.DateTimeFormat('de-DE', { timeZone: TZ, ...opts })
const F = {
time: dtf({ hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }),
day: dtf({ day: '2-digit', month: '2-digit' }),
month: dtf({ month: 'short', year: 'numeric' }),
year: dtf({ year: 'numeric' }),
legend: dtf({ day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', hourCycle: 'h23' }),
}
// Welches Format passt zu einem Tick-Abstand (Sekunden)?
export function axisTimeKind(incrSec) {
if (incrSec < 86400) return 'time'
if (incrSec < 86400 * 28) return 'day'
if (incrSec < 86400 * 360) return 'month'
return 'year'
}
// Tick (Sekunden) -> Text. Bei Tagesgrenzen innerhalb von Sub-Tages-Achsen das Datum zeigen.
export function formatAxisTick(sec, incrSec) {
const kind = axisTimeKind(incrSec)
const d = new Date(sec * 1000)
if (kind === 'time' && F.time.format(d) === '00:00') return F.day.format(d)
return F[kind].format(d)
}
// Legende: "30.09.2026, 11:20"
export function formatLegendTime(sec) {
if (sec === null || sec === undefined) return '–'
return F.legend.format(new Date(sec * 1000))
}
// "seit"-Zeitpunkt in Warnungen, immer Berliner Zeit.
export function formatSince(ts) {
if (!ts) return ''
return new Date(ts).toLocaleString('de-DE', { dateStyle: 'short', timeStyle: 'short', timeZone: 'Europe/Berlin' })
}