diff --git a/src/lib/ui/campaigns.ts b/src/lib/ui/campaigns.ts index b773519..db97e61 100644 --- a/src/lib/ui/campaigns.ts +++ b/src/lib/ui/campaigns.ts @@ -1,3 +1,22 @@ +import { statusPresentation, type StatusTone } from './status.js'; + +export type CampaignServerGroup = 'attention' | 'processing' | 'queued' | 'complete' | 'inactive'; + +/** Progress comes from recorded state, not the error field, which also contains routine stage messages. */ +export function campaignServerStatus(server: { + restart_state: string; server_deleted_at?: string | null; restarted_at: string | null; +}, files: { apply_state: string }[] = []): { group: CampaignServerGroup; label: string; tone: StatusTone } { + if (server.restart_state === 'done') return { group: 'complete', label: 'Complete', tone: 'online' }; + if (server.server_deleted_at) return { group: 'inactive', label: 'Deleted before activation', tone: 'neutral' }; + if (['skipped', 'cancelled'].includes(server.restart_state)) return { group: 'inactive', ...statusPresentation(server.restart_state) }; + if (['failed', 'manual', 'held'].includes(server.restart_state)) { + return { group: 'attention', ...statusPresentation(server.restart_state), tone: server.restart_state === 'failed' ? 'danger' : 'warning' }; + } + if (server.restarted_at) return { group: 'processing', label: 'Verifying health', tone: 'info' }; + if (files.some(file => file.apply_state === 'applying')) return { group: 'processing', label: 'Applying files', tone: 'info' }; + return { group: 'queued', label: 'Queued', tone: 'neutral' }; +} + /** Load only the requested history, respecting the API's per-request page bound. */ export async function fetchCampaigns(filters: Record, count: number, signal?: AbortSignal): Promise<{ deployments: T[]; total: number }> { const deployments: T[] = []; diff --git a/src/routes/campaigns/[id]/+page.svelte b/src/routes/campaigns/[id]/+page.svelte index a3a60ae..4df3c99 100644 --- a/src/routes/campaigns/[id]/+page.svelte +++ b/src/routes/campaigns/[id]/+page.svelte @@ -1,22 +1,21 @@