mirror of
https://github.com/samvallad33/vestige.git
synced 2026-04-25 00:36:22 +02:00
feat(dashboard): surface Heartbeat uptime_secs in the sidebar footer
The Heartbeat event has shipped since v2.0.5 carrying uptime_secs,
memory_count, avg_retention, suppressed_count. Three of the four were
already wired into the sidebar footer (memory count, retention,
forgetting indicator). uptime_secs was the one field that fired every
30 seconds into a silent void.
Added:
- `uptimeSeconds` derived store + `formatUptime(secs)` helper in
websocket.ts. The helper picks the two most significant units so the
sidebar stays tight: "3d 4h" instead of "3d 4h 22m 17s", "18m 43s"
for shorter runs, "47s" on a fresh boot.
- New line in the sidebar status footer between retention and the
ForgettingIndicator: "up 3d 4h" with a hover tooltip ("MCP server
uptime") for discoverability. Hidden at sub-lg breakpoints to match
the existing responsive pattern of the surrounding text.
Zero backend work — the data was already on the wire. This is pure
UI gap closure: four of four Heartbeat fields now visible.
svelte-check clean (580 files, 0 errors).
This commit is contained in:
parent
fc6dca6338
commit
7a3d30914d
2 changed files with 36 additions and 2 deletions
|
|
@ -105,3 +105,24 @@ export const avgRetention = derived(websocket, $ws =>
|
|||
export const suppressedCount = derived(websocket, $ws =>
|
||||
($ws.lastHeartbeat?.data?.suppressed_count as number) ?? 0
|
||||
);
|
||||
|
||||
// v2.0.7: uptime of the MCP server in seconds, refreshed every heartbeat.
|
||||
// Exposed raw so callers can format as they like; the helper below is the
|
||||
// standard compact format ("3d 4h 22m", "18m", "47s") used in the sidebar.
|
||||
export const uptimeSeconds = derived(websocket, $ws =>
|
||||
($ws.lastHeartbeat?.data?.uptime_secs as number) ?? 0
|
||||
);
|
||||
|
||||
export function formatUptime(secs: number): string {
|
||||
if (!Number.isFinite(secs) || secs < 0) return '—';
|
||||
const d = Math.floor(secs / 86_400);
|
||||
const h = Math.floor((secs % 86_400) / 3_600);
|
||||
const m = Math.floor((secs % 3_600) / 60);
|
||||
const s = Math.floor(secs % 60);
|
||||
// Compact representation: show the two most significant units so the
|
||||
// sidebar stays readable ("3d 4h" not "3d 4h 22m 17s", "18m 43s", etc).
|
||||
if (d > 0) return h > 0 ? `${d}d ${h}h` : `${d}d`;
|
||||
if (h > 0) return m > 0 ? `${h}h ${m}m` : `${h}h`;
|
||||
if (m > 0) return s > 0 ? `${m}m ${s}s` : `${m}m`;
|
||||
return `${s}s`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,15 @@
|
|||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { base } from '$app/paths';
|
||||
import { websocket, isConnected, memoryCount, avgRetention, suppressedCount } from '$stores/websocket';
|
||||
import {
|
||||
websocket,
|
||||
isConnected,
|
||||
memoryCount,
|
||||
avgRetention,
|
||||
suppressedCount,
|
||||
uptimeSeconds,
|
||||
formatUptime,
|
||||
} from '$stores/websocket';
|
||||
import ForgettingIndicator from '$lib/components/ForgettingIndicator.svelte';
|
||||
|
||||
let { children } = $props();
|
||||
|
|
@ -141,9 +149,14 @@
|
|||
<div class="w-2 h-2 rounded-full {$isConnected ? 'bg-recall animate-pulse-glow' : 'bg-decay'}"></div>
|
||||
<span class="hidden lg:block text-dim">{$isConnected ? 'Connected' : 'Offline'}</span>
|
||||
</div>
|
||||
<div class="hidden lg:block text-xs text-muted">
|
||||
<div class="hidden lg:block text-xs text-muted space-y-0.5">
|
||||
<div>{$memoryCount} memories</div>
|
||||
<div>{($avgRetention * 100).toFixed(0)}% retention</div>
|
||||
<!-- v2.0.7: surface uptime_secs from the Heartbeat event. Fires
|
||||
every 30s so this self-refreshes. "up 3d 4h" format. -->
|
||||
{#if $uptimeSeconds > 0}
|
||||
<div title="MCP server uptime">up {formatUptime($uptimeSeconds)}</div>
|
||||
{/if}
|
||||
</div>
|
||||
{#if $suppressedCount > 0}
|
||||
<div class="hidden lg:block pt-1">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue