drift update
This commit is contained in:
@@ -33,7 +33,13 @@
|
||||
scripts: DepScript[];
|
||||
}
|
||||
|
||||
interface DriftFile { relPath: string; size: number; sha256: string }
|
||||
interface DriftFile {
|
||||
relPath: string;
|
||||
size: number;
|
||||
sha256: string;
|
||||
kind: 'script' | 'config' | 'plugin' | 'baseline';
|
||||
driftKind: 'untracked' | 'missing';
|
||||
}
|
||||
interface DriftServer { server: string; files: DriftFile[] }
|
||||
interface DriftPreview { totalDrift: number; servers: DriftServer[] }
|
||||
|
||||
@@ -61,9 +67,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
let driftCounts = $derived.by(() => {
|
||||
if (!drift) return { untracked: 0, missing: 0 };
|
||||
let u = 0, m = 0;
|
||||
for (const s of drift.servers) for (const f of s.files) {
|
||||
if (f.driftKind === 'untracked') u++; else m++;
|
||||
}
|
||||
return { untracked: u, missing: m };
|
||||
});
|
||||
|
||||
async function runDrift(): Promise<void> {
|
||||
if (!drift || drift.totalDrift === 0) return;
|
||||
if (!confirm(`Remove ${drift.totalDrift} untracked file(s) across ${drift.servers.length} server(s)?`)) return;
|
||||
const parts: string[] = [];
|
||||
if (driftCounts.untracked > 0) parts.push(`delete ${driftCounts.untracked} untracked file(s)`);
|
||||
if (driftCounts.missing > 0) parts.push(`restore ${driftCounts.missing} missing artifact(s)`);
|
||||
if (!confirm(`Reconcile drift on ${drift.servers.length} server(s)? Will ${parts.join(' and ')}.`)) return;
|
||||
running = true;
|
||||
flash = null;
|
||||
try {
|
||||
@@ -75,10 +93,20 @@
|
||||
const body = (await res.json()) as {
|
||||
ok: boolean;
|
||||
error?: string;
|
||||
result?: { deploymentId: string | null; totalRemoved: number; totalServers: number };
|
||||
result?: {
|
||||
deploymentId: string | null;
|
||||
totalRemoved: number;
|
||||
totalRestored?: number;
|
||||
totalServers: number;
|
||||
};
|
||||
};
|
||||
if (!body.ok) { flash = body.error ?? 'drift run failed'; return; }
|
||||
flash = `removed ${body.result?.totalRemoved ?? 0} files across ${body.result?.totalServers ?? 0} servers`;
|
||||
const removed = body.result?.totalRemoved ?? 0;
|
||||
const restored = body.result?.totalRestored ?? 0;
|
||||
const parts2: string[] = [];
|
||||
if (removed > 0) parts2.push(`removed ${removed}`);
|
||||
if (restored > 0) parts2.push(`restored ${restored}`);
|
||||
flash = `${parts2.join(', ') || 'no'} file(s) across ${body.result?.totalServers ?? 0} server(s)`;
|
||||
await Promise.all([loadDeployments(), scanDrift()]);
|
||||
} finally {
|
||||
running = false;
|
||||
@@ -149,11 +177,11 @@
|
||||
{:else}
|
||||
<section class="drift-panel">
|
||||
<div class="drift-head">
|
||||
<h2>Drift{drift ? ` · ${drift.totalDrift} untracked file${drift.totalDrift === 1 ? '' : 's'}` : ''}</h2>
|
||||
<h2>Drift{drift ? ` · ${driftCounts.untracked} untracked, ${driftCounts.missing} missing` : ''}</h2>
|
||||
<div class="drift-actions">
|
||||
<button onclick={scanDrift} disabled={scanning || running}>{scanning ? 'scanning…' : 'rescan'}</button>
|
||||
<button class="primary" onclick={runDrift} disabled={running || scanning || !drift || drift.totalDrift === 0}>
|
||||
{running ? 'removing…' : 'remove drift'}
|
||||
{running ? 'reconciling…' : 'reconcile drift'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -164,10 +192,13 @@
|
||||
{:else}
|
||||
{#each drift.servers as s (s.server)}
|
||||
<div class="drift-server">
|
||||
<div class="drift-server-head mono">{s.server} · {s.files.length} file{s.files.length === 1 ? '' : 's'}</div>
|
||||
<div class="drift-server-head mono">{s.server} · {s.files.length} entr{s.files.length === 1 ? 'y' : 'ies'}</div>
|
||||
<div class="drift-files">
|
||||
{#each s.files as f (f.relPath)}
|
||||
<span class="drift-file mono" title="{f.size}B · {f.sha256.slice(0, 12)}">{f.relPath}</span>
|
||||
{#each s.files as f (f.driftKind + ':' + f.kind + ':' + f.relPath)}
|
||||
<span
|
||||
class="drift-file mono {f.driftKind}"
|
||||
title="[{f.kind}] {f.driftKind} · {f.size}B · {f.sha256.slice(0, 12)}"
|
||||
>[{f.driftKind === 'missing' ? '+' : '−'} {f.kind}] {f.relPath}</span>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
@@ -363,12 +394,20 @@
|
||||
.drift-server-head { color: var(--cream); font-size: var(--text-mono); margin-bottom: 6px; }
|
||||
.drift-files { display: flex; flex-wrap: wrap; gap: 6px; }
|
||||
.drift-file {
|
||||
background: rgba(255, 48, 80, 0.08);
|
||||
border: 1px solid rgba(255, 48, 80, 0.25);
|
||||
color: var(--danger-500);
|
||||
padding: 3px 8px;
|
||||
border-radius: var(--r-sm);
|
||||
font-size: var(--text-mono-sm);
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.drift-file.untracked {
|
||||
background: rgba(255, 48, 80, 0.08);
|
||||
border-color: rgba(255, 48, 80, 0.25);
|
||||
color: var(--danger-500);
|
||||
}
|
||||
.drift-file.missing {
|
||||
background: rgba(255, 176, 32, 0.08);
|
||||
border-color: rgba(255, 176, 32, 0.3);
|
||||
color: var(--amber-500);
|
||||
}
|
||||
.flash { color: var(--spark-400); font-family: var(--font-mono); font-size: var(--text-mono); margin-top: 12px; }
|
||||
.mono { font-family: var(--font-mono); }
|
||||
|
||||
Reference in New Issue
Block a user