Improve operational UX, recovery flows, and action safety

Implement the approved UX review across Fleet, Betas, Library, deployments, and Settings. Add reviewed promotion and reconciliation plans, atomic queued-removal cancellation, recoverable beta drafts and launch inputs, accessible controls, and mobile improvements.

Validated with 473 tests, a clean typecheck, production build, and isolated desktop/mobile browser walkthroughs. Include the review and implementation coverage notes.
This commit is contained in:
2026-09-19 21:34:34 -04:00
parent 940f81e6ca
commit 8ac420fe61
83 changed files with 2574 additions and 1190 deletions
+18 -13
View File
@@ -1,10 +1,11 @@
import { json } from '@sveltejs/kit';
import { runDriftDeployment, scanFleetDrift } from '$lib/server/fleet/drift.js';
import { DriftPlanChanged, previewDrift, runDriftDeployment } from '$lib/server/fleet/drift.js';
import { kick } from '$lib/server/pipeline/worker.js';
// GET returns the current drift plan for the whole fleet without touching disk.
export async function GET() {
const entries = await scanFleetDrift();
const plan = await previewDrift();
const entries = plan.files.map(file => ({ ...file, size: file.afterSize ?? file.beforeSize ?? 0, sha256: file.afterSha256 ?? file.beforeSha256 ?? '' }));
const byServer = new Map<
string,
Array<{ relPath: string; size: number; sha256: string; kind: string; driftKind: string }>
@@ -21,21 +22,25 @@ export async function GET() {
byServer.set(e.server, arr);
}
return json({
totalDrift: entries.length,
totalDrift: entries.length, scannedAt: plan.scannedAt,
servers: [...byServer.entries()].map(([server, files]) => ({ server, files }))
});
}
// POST removes drift and creates a drift deployment. Body: { servers?: string[], dryRun?: boolean }
export async function POST({ request }: { request: Request }) {
const body = (await request
.json()
.catch(() => ({}))) as { servers?: string[]; dryRun?: boolean };
const result = await runDriftDeployment({
servers: body.servers,
dryRun: body.dryRun ?? false,
triggeredBy: 'ui'
});
if (result.deploymentId) void kick();
return json({ ok: true, result });
const body = await request.json().catch(() => null);
if (!body || (body.servers !== undefined && (!Array.isArray(body.servers) || !body.servers.every((server: unknown) => typeof server === 'string')))) {
return json({ ok: false, error: 'Provide the server IDs to review.' }, { status: 400 });
}
try {
if (body.dryRun === true) return json({ ok: true, plan: await previewDrift(body.servers) });
if (typeof body.expectedFingerprint !== 'string' || !body.expectedFingerprint) return json({ ok: false, error: 'Review a reconciliation plan before applying changes.' }, { status: 400 });
const result = await runDriftDeployment({ servers: body.servers, expectedFingerprint: body.expectedFingerprint, triggeredBy: 'ui' });
if (result.deploymentId) void kick();
return json({ ok: true, result });
} catch (error) {
if (error instanceof DriftPlanChanged) return json({ ok: false, error: error.message, plan: error.plan }, { status: 409 });
return json({ ok: false, error: (error as Error).message }, { status: 400 });
}
}