Add configurable history and storage retention policies

This commit is contained in:
2026-10-05 22:48:04 -04:00
parent 7c98df4fb0
commit 3952c4c938
37 changed files with 963 additions and 82 deletions
+4 -2
View File
@@ -31,6 +31,7 @@
attempts: number; error: string | null;
}
interface Detail {
fileContentsExpired?: boolean;
deployment: {
id: string; action: string; started_at: string;
finished_at: string | null; triggered_by: string | null; beta_id?: number | null;
@@ -96,7 +97,7 @@
diffOpen = true; diffLoading = true; diffError = ''; openFile = null;
try {
const response = await fetch('/api/campaigns/' + id + '/file/' + f.id);
if (!response.ok) throw new Error('Could not load this file comparison. Close and select it again to retry.');
if (!response.ok) throw new Error(response.status === 410 ? 'File contents expired under the retention policy.' : 'Could not load this file comparison. Close and select it again to retry.');
const body = await response.json();
if (id === $page.params.id && current === diffRequest) openFile = {id:f.id, ...body};
} catch (error) { if (id === $page.params.id && current === diffRequest) diffError = (error as Error).message; }
@@ -139,6 +140,7 @@
{/snippet}
</SectionHeader>
<BackLink fallback="/campaigns" />
{#if detail.fileContentsExpired}<p role="status">File contents have expired under the retention policy. File comparisons and rollback are unavailable.</p>{/if}
<section class="outcome" aria-label="Campaign outcome">
<h2>{completed} / {detail.servers.length} servers activated{unresolved ? ` · ${unresolved} unresolved` : ''}{withdrawn ? ` · ${withdrawn} withdrawn` : ''}{deletedIncomplete ? ` · ${deletedIncomplete} deleted before activation` : ''}</h2>
@@ -209,7 +211,7 @@
<h3><HistoricalServerIdentity name={srv} deletedAt={detail.servers.find(server => server.server === srv)?.server_deleted_at} /></h3>
<div class="file-rows">
{#each files as f (f.id)}
<button class="file-row" onclick={() => loadDiff(f)}>
<button class="file-row" disabled={detail.fileContentsExpired} onclick={() => loadDiff(f)}>
<Badge variant={verbVariant(f.verb)} size="sm" uppercase>{f.verb}</Badge>
{#if f.apply_state !== 'applied'}<Badge variant="neutral" size="sm">{f.apply_state === 'pending' ? 'Queued' : f.apply_state === 'applying' ? 'Needs inspection' : 'Cancelled'}</Badge>{/if}
<span class="path">{f.rel_path}</span>