diff --git a/packages/proxy/web/src/lib/components/IdleTimer.svelte b/packages/proxy/web/src/lib/components/IdleTimer.svelte
index 27c8f8c..25e7abd 100644
--- a/packages/proxy/web/src/lib/components/IdleTimer.svelte
+++ b/packages/proxy/web/src/lib/components/IdleTimer.svelte
@@ -1,4 +1,6 @@
Idle Timer
- {formatTime(remainingSeconds)}
+ {formatTime(localRemaining)}
until idle check
Last activity: {formatDate(lastActivity)}
@@ -38,6 +63,9 @@
font-weight: 700;
font-variant-numeric: tabular-nums;
}
+ .time.urgent {
+ color: var(--orange);
+ }
.label {
font-size: 0.75rem;
color: var(--text-muted);
diff --git a/packages/proxy/web/src/lib/components/ServiceList.svelte b/packages/proxy/web/src/lib/components/ServiceList.svelte
index 0991708..2e1706d 100644
--- a/packages/proxy/web/src/lib/components/ServiceList.svelte
+++ b/packages/proxy/web/src/lib/components/ServiceList.svelte
@@ -6,6 +6,14 @@
}
let { services }: Props = $props();
+
+ function timeAgo(iso: string | null): string {
+ if (!iso) return 'never';
+ const diff = Math.floor((Date.now() - new Date(iso).getTime()) / 1000);
+ if (diff < 5) return 'just now';
+ if (diff < 60) return `${diff}s ago`;
+ return `${Math.floor(diff / 60)}m ago`;
+ }
@@ -19,7 +27,13 @@
{service.name}
- {service.host}
+ {service.target}
+
+ {service.healthy ? 'Healthy' : 'Unhealthy'}
+ {#if service.lastCheck}
+ · checked {timeAgo(service.lastCheck)}
+ {/if}
+
{/each}
@@ -50,7 +64,7 @@
width: 8px;
height: 8px;
border-radius: 50%;
- background: var(--text-dim);
+ background: var(--red);
flex-shrink: 0;
}
.dot.healthy {
@@ -64,8 +78,14 @@
font-weight: 500;
font-size: 0.875rem;
}
- .service-host {
+ .service-target {
font-size: 0.75rem;
color: var(--text-muted);
+ font-family: monospace;
+ }
+ .service-meta {
+ font-size: 0.7rem;
+ color: var(--text-dim);
+ margin-top: 0.15rem;
}
diff --git a/packages/proxy/web/src/lib/stores/machine.ts b/packages/proxy/web/src/lib/stores/machine.ts
index 7959dcf..bb0bd66 100644
--- a/packages/proxy/web/src/lib/stores/machine.ts
+++ b/packages/proxy/web/src/lib/stores/machine.ts
@@ -11,6 +11,7 @@ export const machineState = derived(status, ($s) => $s?.state ?? MachineState.OF
let ws: WebSocket | null = null;
let reconnectTimer: ReturnType
| null = null;
+let pollTimer: ReturnType | null = null;
function getWsUrl(): string {
const proto = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
@@ -20,13 +21,14 @@ function getWsUrl(): string {
export function connectWs(): void {
if (ws) return;
+ startPolling();
+
try {
ws = new WebSocket(getWsUrl());
ws.onopen = () => {
connected.set(true);
error.set(null);
- // Fetch full status on connect
refreshStatus();
};
@@ -78,7 +80,22 @@ export async function refreshStatus(): Promise {
}
}
+function startPolling(): void {
+ if (pollTimer) return;
+ pollTimer = setInterval(() => {
+ refreshStatus();
+ }, 5000);
+}
+
+function stopPolling(): void {
+ if (pollTimer) {
+ clearInterval(pollTimer);
+ pollTimer = null;
+ }
+}
+
export function disconnectWs(): void {
+ stopPolling();
if (reconnectTimer) {
clearTimeout(reconnectTimer);
reconnectTimer = null;