diff --git a/src/lib/server/hosts/overview.ts b/src/lib/server/hosts/overview.ts new file mode 100644 index 0000000..8833d59 --- /dev/null +++ b/src/lib/server/hosts/overview.ts @@ -0,0 +1,16 @@ +import { db } from '../db/index.js'; +import { listHosts } from './index.js'; +import { presentHostPreparation } from './preparation.js'; +import type { Host } from '../../hosts.js'; + +export interface HostOverview extends Host { serverCount: number } + +/** Count assigned servers without loading their telemetry or historical placements. */ +export function hostOverview(): HostOverview[] { + const hosts = listHosts(); + const counts = new Map((db().prepare(`SELECT i.host_id, COUNT(*) AS count FROM native_instances i + JOIN servers s ON s.name = i.server + WHERE i.retired_at IS NULL AND s.destroyed_at IS NULL + GROUP BY i.host_id`).all() as { host_id: string; count: number }[]).map(row => [row.host_id, row.count])); + return hosts.map(host => ({ ...presentHostPreparation(host), serverCount: counts.get(host.id) ?? 0 })); +} diff --git a/src/lib/ui/components/AddHostDrawer.svelte b/src/lib/ui/components/AddHostDrawer.svelte new file mode 100644 index 0000000..6231292 --- /dev/null +++ b/src/lib/ui/components/AddHostDrawer.svelte @@ -0,0 +1,61 @@ + + + +
+ {#if error}{/if} + {#if enrollment} +

{name} created. Run this command with administrator access on that machine.

+ +
+

This single-use command expires {new Date(enrollment.expiresAt).toLocaleString()}. Generate a new installer from host settings if it expires.

+ + {:else} +

Use a Debian 12 or 13 amd64 machine. The agent connects over HTTPS and prepares the runtime and game files automatically.

+
+ +
Advanced settings
+ + +
+ +
+ {/if} +
+
+ + diff --git a/src/lib/ui/components/HostList.svelte b/src/lib/ui/components/HostList.svelte new file mode 100644 index 0000000..e829f3e --- /dev/null +++ b/src/lib/ui/components/HostList.svelte @@ -0,0 +1,40 @@ + + +
+ + {#each hosts as host (host.id)} + {@const status = hostListStatus(host, now)} + {@const stale = hostReadingsStale(host, now)} + + + + + + + + + {/each} +
HostStatusServersCPUMemory used / totalDisk used / total
{host.name}{#if host.hostname && host.hostname !== host.name}{host.hostname}{/if} + {#if stale && host.lastHeartbeat}Resource readings stale{/if}{status.label}{#if status.detail}{status.detail}{/if}{host.serverCount}{hostCpuUsage(host.inventory.cpuUsagePercent)}{hostUsedSpace(host.inventory.memoryTotal, host.inventory.memoryAvailable)}{hostUsedSpace(host.inventory.storageTotal, host.inventory.storageAvailable)}
+ + diff --git a/src/lib/ui/components/primitives/Dialog.svelte b/src/lib/ui/components/primitives/Dialog.svelte index 599c959..06b633a 100644 --- a/src/lib/ui/components/primitives/Dialog.svelte +++ b/src/lib/ui/components/primitives/Dialog.svelte @@ -2,8 +2,8 @@ import { tick, type Snippet } from 'svelte'; import Button from './Button.svelte'; - let { open = $bindable(false), title, description, busy = false, wide = false, children, actions }: - { open?: boolean; title: string; description?: string; busy?: boolean; wide?: boolean; children?: Snippet; actions?: Snippet } = $props(); + let { open = $bindable(false), title, description, busy = false, wide = false, drawer = false, children, actions }: + { open?: boolean; title: string; description?: string; busy?: boolean; wide?: boolean; drawer?: boolean; children?: Snippet; actions?: Snippet } = $props(); const id = $props.id(); let dialog = $state(); let returnFocus: HTMLElement | null = null; @@ -22,7 +22,7 @@ } - { if (busy) event.preventDefault(); }} onclose={closed} onclick={event => { if (event.target === dialog) { const r = dialog!.getBoundingClientRect(); if (event.clientX < r.left || event.clientX > r.right || event.clientY < r.top || event.clientY > r.bottom) close(); } }}>

{title}

{#if description}

{description}

{/if}
@@ -33,6 +33,7 @@ diff --git a/src/routes/hosts/[id]/+page.svelte b/src/routes/hosts/[id]/+page.svelte index b33de6e..ce10985 100644 --- a/src/routes/hosts/[id]/+page.svelte +++ b/src/routes/hosts/[id]/+page.svelte @@ -71,7 +71,7 @@ {host?.name ?? 'Host'} · Electric Cherry
{#snippet crumbs()}{/snippet} - {#snippet actions()}{#if canManage && host && (!cleaning || host.decommission?.retryable)}{/if}{/snippet} + {#snippet actions()}{#if canManage && host && (!cleaning || host.decommission?.retryable)}
More actions
{/if}{/snippet}
{#if error}{/if}{#if notice}

{notice}

{/if} @@ -155,6 +155,11 @@