Simplify campaign list and add searchable status filters

This commit is contained in:
2026-10-06 16:21:38 -04:00
parent 7985f1202f
commit ba015ca4c7
6 changed files with 327 additions and 389 deletions
+32 -1
View File
@@ -6,6 +6,8 @@
import Dialog from '$ui/components/primitives/Dialog.svelte';
import HistoricalServerIdentity from '$ui/components/HistoricalServerIdentity.svelte';
import { page } from '$app/stores';
import { goto } from '$app/navigation';
import { confirmAction } from '$ui/confirm.js';
import DiffViewer from '$ui/components/DiffViewer.svelte';
import Badge from '$ui/components/primitives/Badge.svelte';
import Button from '$ui/components/primitives/Button.svelte';
@@ -35,6 +37,7 @@
deployment: {
id: string; action: string; started_at: string;
finished_at: string | null; triggered_by: string | null; beta_id?: number | null;
rolled_back_by: string | null;
};
servers: ServerRow[];
files: FileRow[];
@@ -46,6 +49,8 @@
let loadError = $state('');
let resuming = $state(false);
let resumeError = $state('');
let rollingBack = $state(false);
let rollbackError = $state('');
let request = 0;
let diffOpen = $state(false);
let diffError = $state('');
@@ -96,7 +101,7 @@
}
}
$effect(() => { $page.params.id; detail = null; openFile = null; diffOpen = false; loadError = ''; filter = 'all'; expandedServers = []; copyStatus = ''; void loadDetail(); });
$effect(() => { $page.params.id; detail = null; openFile = null; diffOpen = false; loadError = ''; rollbackError = ''; filter = 'all'; expandedServers = []; copyStatus = ''; void loadDetail(); });
onMount(() => pollVisible(loadDetail, 5000, false));
@@ -110,6 +115,24 @@
finally { resuming = false; }
}
async function rollback() {
if (!detail || rollingBack) return;
const id = detail.deployment.id;
const servers = detail.servers.filter(server => !server.server_deleted_at).length;
if (!await confirmAction({ title: 'Roll back promotion?', message: `Restore the previous files on ${servers} server${servers === 1 ? '' : 's'}. Changes will wait for safe activation.`, confirmLabel: 'Roll back', danger: true })) return;
if ($page.params.id !== id) return;
rollingBack = true; rollbackError = '';
try {
const response = await fetch(`/api/campaigns/${encodeURIComponent(id)}/rollback`, { method: 'POST' });
const body = await response.json();
if (!response.ok || !body.ok) throw new Error(body.error ?? 'Could not roll back promotion.');
if ($page.params.id !== id) return;
await goto(contextHref(`/campaigns/${encodeURIComponent(body.result.deploymentId)}`, $page.url));
} catch (error) {
if ($page.params.id === id) rollbackError = (error as Error).message;
} finally { rollingBack = false; }
}
async function loadDiff(f: FileRow) {
retryFile = f;
const id = $page.params.id;
@@ -158,7 +181,15 @@
{ label: action }
]} />
{/snippet}
{#snippet actions()}
{#if detail?.deployment.rolled_back_by}
<Button size="sm" href={contextHref(`/campaigns/${encodeURIComponent(detail.deployment.rolled_back_by)}`, $page.url)}>View rollback</Button>
{:else if detail && action === 'promote' && !detail.fileContentsExpired && detail.servers.some(server => !server.server_deleted_at)}
<Button variant="danger" size="sm" onclick={rollback} loading={rollingBack} disabled={rollingBack}>Roll back promotion</Button>
{/if}
{/snippet}
</SectionHeader>
{#if rollbackError}<p class="err" role="alert">{rollbackError}</p>{/if}
<div class="metadata">
<span>Started {fmt(detail.deployment.started_at)}</span>
{#if detail.deployment.beta_id}<span>Source: <a href={contextHref(`/betas/${detail.deployment.beta_id}`, $page.url)}>Beta #{detail.deployment.beta_id}</a></span>{/if}