repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
The Living OS cockpit
stars
latest
clone command
git clone gitlawb://did:key:z6Mku78K...XywC/living-os-cockp...git clone gitlawb://did:key:z6Mku78K.../living-os-cockp...59751530feat: surface worker supervisor health in live work5h ago| #1 | 'use client'; |
| #2 | import useSWR from 'swr'; |
| #3 | import { swrFetcher } from '@/lib/client-api'; |
| #4 | |
| #5 | const fetcher = swrFetcher; |
| #6 | |
| #7 | function relTime(ts: number): string { |
| #8 | const diff = Date.now() - ts; |
| #9 | if (diff < 60_000) return `${Math.floor(diff/1000)}s ago`; |
| #10 | if (diff < 3600_000) return `${Math.floor(diff/60000)}m ago`; |
| #11 | if (diff < 86400_000) return `${Math.floor(diff/3600000)}h ago`; |
| #12 | return `${Math.floor(diff/86400000)}d ago`; |
| #13 | } |
| #14 | |
| #15 | const LEVEL_COLOR: Record<string, string> = { |
| #16 | info: 'text-[color:var(--text-2)]', |
| #17 | success: 'text-green-400', |
| #18 | warning: 'text-amber-400', |
| #19 | error: 'text-red-400', |
| #20 | }; |
| #21 | |
| #22 | export default function EventsFeed() { |
| #23 | const { data } = useSWR('/api/events', fetcher, { refreshInterval: 10000 }); |
| #24 | const events = data?.events ?? []; |
| #25 | |
| #26 | if (events.length === 0) { |
| #27 | return <div className="text-sm text-[color:var(--text-3)]">No events yet. Backups, audits, and signups will appear here.</div>; |
| #28 | } |
| #29 | |
| #30 | return ( |
| #31 | <div className="space-y-1.5 max-h-64 overflow-y-auto"> |
| #32 | {events.map((e: any, i: number) => ( |
| #33 | <div key={i} className="text-xs flex gap-2 items-start py-1 border-b border-[color:var(--border)] last:border-0"> |
| #34 | <span className="text-[color:var(--text-4)] font-mono w-12 shrink-0">{relTime(e.ts)}</span> |
| #35 | <span className={`${LEVEL_COLOR[e.level]} font-medium w-16 shrink-0`}>{e.kind}</span> |
| #36 | <span className="text-[color:var(--text-2)] flex-1">{e.summary}</span> |
| #37 | </div> |
| #38 | ))} |
| #39 | </div> |
| #40 | ); |
| #41 | } |
| #42 |