export function formatBoolean(value) { if (value == null) return 'Unknown'; return value ? 'Yes' : 'No'; } export function formatTimestamp(value) { if (!value) return 'Unavailable'; const date = new Date(value); if (Number.isNaN(date.getTime())) return 'Unavailable'; return date.toLocaleString(); } export function formatAge(value) { if (value == null) return 'Unavailable'; const numeric = Number(value); if (!Number.isFinite(numeric)) return 'Unavailable'; const ageMs = Math.max(0, Math.floor(numeric)); if (ageMs < 1000) return `${ageMs} ms`; const seconds = Math.floor(ageMs / 1000); if (seconds < 60) return `${seconds}s`; const minutes = Math.floor(seconds / 60); const remainingSeconds = seconds % 60; if (minutes < 60) { return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`; } const hours = Math.floor(minutes / 60); const remainingMinutes = minutes % 60; if (hours < 24) { return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`; } const days = Math.floor(hours / 24); const remainingHours = hours % 24; return remainingHours > 0 ? `${days}d ${remainingHours}h` : `${days}d`; } export function formatAgeFromTimestamp(value, now = Date.now()) { if (!value) return 'Unavailable'; const timestamp = new Date(value).getTime(); if (Number.isNaN(timestamp)) return 'Unavailable'; return formatAge(now - timestamp); } export function formatBytes(value) { const numeric = Number(value); if (!Number.isFinite(numeric)) return 'Unavailable'; const units = ['B', 'KiB', 'MiB', 'GiB', 'TiB']; let amount = Math.max(0, numeric); let unitIndex = 0; while (amount >= 1024 && unitIndex < units.length - 1) { amount /= 1024; unitIndex += 1; } const digits = amount >= 100 || unitIndex === 0 ? 0 : amount >= 10 ? 1 : 2; return `${amount.toFixed(digits)} ${units[unitIndex]}`; } export function formatEur(value) { if (value == null || value === '') return 'Unavailable'; const numeric = Number(value); if (!Number.isFinite(numeric)) return String(value); return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'EUR', maximumFractionDigits: 2, }).format(numeric); } export function signedClass(value) { const numeric = Number(value); if (!Number.isFinite(numeric)) return ''; if (numeric > 0) return 'value-positive'; if (numeric < 0) return 'value-negative'; return ''; } export function truncateMiddle(value, maxLength = 40) { const text = String(value || ''); if (!text || text.length <= maxLength) return text; const visible = Math.max(8, maxLength - 1); const startLength = Math.ceil(visible / 2); const endLength = Math.floor(visible / 2); return `${text.slice(0, startLength)}…${text.slice(-endLength)}`; } export function stringifyJson(value) { return JSON.stringify(value, null, 2); }