From 6807e353e3362a7d3c38d327227290659d922ff1 Mon Sep 17 00:00:00 2001 From: dtoro Date: Sun, 12 Jul 2026 11:07:36 +0200 Subject: [PATCH] feat(web): redesign Overview as the homepage with a living graph backdrop Overview replaces Tasks as the default route: a centered new-task entry with live fleet metrics, a scrollable/filterable task table, and an ambient canvas rendering of the real entity graph (autonomous camera drift + mouse parallax) behind it. Tasks sidebar entry is removed; its status-bucketing logic moves to lib/tasks.ts for reuse. Co-Authored-By: Claude Sonnet 5 --- web/src/App.svelte | 25 +- web/src/lib/components/GraphBackground.svelte | 233 ++++++++++ web/src/lib/tasks.ts | 53 +++ web/src/pages/Overview.svelte | 428 +++++++++--------- web/src/pages/Tasks.svelte | 213 --------- 5 files changed, 510 insertions(+), 442 deletions(-) create mode 100644 web/src/lib/components/GraphBackground.svelte create mode 100644 web/src/lib/tasks.ts delete mode 100644 web/src/pages/Tasks.svelte diff --git a/web/src/App.svelte b/web/src/App.svelte index 9fd7efb..89876cb 100644 --- a/web/src/App.svelte +++ b/web/src/App.svelte @@ -1,6 +1,5 @@ + +
+ +
diff --git a/web/src/lib/tasks.ts b/web/src/lib/tasks.ts new file mode 100644 index 0000000..de8f131 --- /dev/null +++ b/web/src/lib/tasks.ts @@ -0,0 +1,53 @@ +// Shared task-status helpers. Used by the Overview homepage (and previously the +// standalone Tasks board) to map a session's lifecycle onto a small set of +// display buckets, styles, and filters. +import type { Session } from '$lib/api' + +export type Bucket = 'running' | 'input' | 'done' | 'failed' + +export function bucket(s: Session): Bucket { + switch (s.status) { + case 'awaiting_input': + return 'input' + case 'done': + return s.outcome === 'failure' ? 'failed' : 'done' + case 'failed': + return 'failed' + default: + return 'running' // active | planning | executing | undefined + } +} + +export interface StatusStyle { + label: string + dot: string + pulse: boolean +} + +export function statusStyle(s: Session): StatusStyle { + switch (bucket(s)) { + case 'input': + return { label: 'Needs input', dot: 'bg-warning', pulse: true } + case 'done': + return { label: s.outcome === 'partial' ? 'Done · partial' : 'Done', dot: 'bg-success', pulse: false } + case 'failed': + return { label: 'Failed', dot: 'bg-destructive', pulse: false } + default: + return { label: 'Running', dot: 'bg-primary', pulse: true } + } +} + +export const FILTERS: { id: 'all' | Bucket; label: string }[] = [ + { id: 'all', label: 'All' }, + { id: 'running', label: 'Running' }, + { id: 'input', label: 'Needs input' }, + { id: 'done', label: 'Done' }, + { id: 'failed', label: 'Failed' } +] + +// Task events that should trigger a session-board refetch. +export const TASK_EVENTS = new Set(['task.status', 'goal.set', 'question.raised', 'question.answered']) + +export function heading(s: Session): string { + return s.goal || s.title || 'Untitled task' +} diff --git a/web/src/pages/Overview.svelte b/web/src/pages/Overview.svelte index be9fea4..5a073f9 100644 --- a/web/src/pages/Overview.svelte +++ b/web/src/pages/Overview.svelte @@ -1,64 +1,28 @@ -
-

Overview

+
+ - {#if loading} -
- {#each Array(4) as _} - - {/each} -
- {:else if summary} -
- - - Entities - - {totalEntities} - - - {entityTypeCount} types - - - -
- {#each topTypes as [type, count]} - {type}: {count} - {/each} -
-
Across the fleet
-
-
- - - - Fleet health - - {summary.health.healthy} / {totalMonitored} - - - {#if healthTone === 'ok'} - healthy - {:else if healthTone === 'degraded'} - degraded - {:else} - down - {/if} - - - -
- {summary.health.degraded} degraded · {summary.health.down} down · {summary.health.unknown} unmonitored -
-
Healthy entities as observed by the scheduler
-
-
- - - - -
- - {#if degradedTypes.length} - - - Attention needed - - - {#each degradedTypes as t} - {t.label}: {t.count} - {/each} - - - {/if} - - - - Event rate (6h, 5m buckets) - - -
- {#each summary.event_rate as bucket} -
- {/each} +
+ +
+ +
+
+ Entities + {totalEntities} + {#if entityTypeCount}· {entityTypeCount} types{/if}
- - - {/if} - - - - Live event ticker - - - -
- {#each $liveEvents as ev (ev.id)} -
- {ev.severity} - {new Date(ev.ts).toLocaleTimeString()} - {ev.type} - {ev.source} -
+
+ + Health + {summary?.health.healthy ?? 0} / {totalMonitored} +
+ + +
+ + +
+
+

What should Nomos do?

+

+ Describe a goal — Nomos will plan it, execute it, and report the outcome. +

+
{ + e.preventDefault() + submit() + }} + > +