Simplify launch files history card (Refs #87)

This commit is contained in:
2026-10-09 14:31:59 -04:00
parent da623e8409
commit 15ab41d4a2
3 changed files with 13 additions and 20 deletions
+4 -11
View File
@@ -20,7 +20,6 @@
import ProvisioningProgress from '$ui/components/ProvisioningProgress.svelte';
import ProvisioningActivity from '$ui/components/ProvisioningActivity.svelte';
import LaunchRecipe from '$ui/components/LaunchRecipe.svelte';
import DeployServerDialog from '$ui/components/DeployServerDialog.svelte';
import Freshness from '$ui/components/Freshness.svelte';
import RelativeTime from '$ui/components/RelativeTime.svelte';
import { timestampISO, type Timestamp } from '$lib/time-zone.js';
@@ -33,7 +32,6 @@
loadError: '', actionError: '', notice: '', refreshedAt: initial.generatedAt
});
let now = $state(Date.parse(initial.generatedAt));
let launchOpen = $state(false);
let copyStatus = $state('');
const controller = createProvisioningRefresh<ProvisioningDetail>({ validate: isProvisioningDetail, onChange: value => { view = value; } });
const detail = $derived(view.detail);
@@ -47,11 +45,10 @@
const duration = $derived(finishedAt || active ? elapsedTime(startedAt, finishedAt ? Date.parse(finishedAt) : now) : 'Not recorded');
const serverHref = $derived(deployment && deployment.server_exists && !deployment.server_deleted_at ? `/servers/${encodeURIComponent(deployment.server)}` : null);
const recipeStatus = $derived(detail?.progress?.recipeStatus ?? null);
const recipeHeading = $derived(recipeStatus === 'queued' ? 'Setup captured when queued' : recipeStatus === 'attempted' ? 'Files selected for this attempt' : 'Recorded launch files');
const recipeSelection = $derived(recipeStatus === 'queued' ? 'Captured when queued' : recipeStatus === 'attempted' ? 'Selected when creation began' : 'Recorded setup; selection time unknown');
$effect(() => {
const snapshot = data.detail;
untrack(() => {
launchOpen = false;
copyStatus = '';
now = Date.parse(snapshot.generatedAt);
controller.setOperation(snapshot.deployment.id, snapshot, snapshot.generatedAt);
@@ -186,13 +183,11 @@
{#if pool.holders.length}<details><summary>Current slot holders</summary><ul>{#each pool.holders as holder}<li>{#if holder.id}<a href={`/provisioning/${encodeURIComponent(holder.id)}`}>{serverTitle(holder.server)}</a>{:else}<span>{serverTitle(holder.server)} · operation not recorded</span>{/if}</li>{/each}</ul></details>{/if}
</div>{/each}<p class="small">Capacity snapshot <RelativeTime value={detail.capacity.evaluatedAt} missing="Not recorded" /></p>
</div></Card>{/if}
<Card as="section" padding="md" ariaLabel="Recorded launch inputs"><div class="context-section recipe"><h2>{recipeHeading}</h2>
<Card as="section" padding="md" ariaLabel="Launch files"><div class="context-section recipe"><h2>Launch files</h2>
{#if detail.recipe}
{#if detail.blueprintName}<p>From {detail.blueprintName}</p>{/if}
<p>{recipeStatus === 'queued' ? 'This capture does not pin versions. The latest promoted setup is selected again when creation begins.' : recipeStatus === 'attempted' ? 'These files were selected when creation began. Selection alone does not confirm successful installation.' : 'This is the saved recipe for this operation. The point at which it was selected was not recorded.'}</p>
<p class="small">Captured {@render dateTime(detail.recipe.capturedAt)}</p>
<LaunchRecipe recipe={detail.recipe} historical selectionStatus={recipeStatus} />
<div class="launch-another"><Button variant="ghost" onclick={() => launchOpen = true}>Launch another server →</Button><p>Creates a separate server with a fresh ID and port using the latest promoted files. It does not repair this instance.</p></div>
<p class="small">{recipeSelection} · <RelativeTime value={detail.recipe.capturedAt} missing="Capture time not recorded" /></p>
<LaunchRecipe recipe={detail.recipe} historical />
{:else}<p>{['create', 'rebuild'].includes(deployment.action) ? 'No launch recipe was recorded for this operation.' : 'This operation uses the existing instance. No new launch files were selected.'}</p>{/if}
</div></Card>
<details class="technical-details">
@@ -212,7 +207,6 @@
</details>
</aside>
</div>
{#if detail.recipe}<DeployServerDialog bind:open={launchOpen} sourceDeploymentId={deployment.id} />{/if}
{/key}
{:else}<div class="loading" role="status">Loading provisioning operation…</div>{/if}
</div>
@@ -244,7 +238,6 @@
.copy-link { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; font-size: var(--text-xs); color: var(--text-secondary); }
.related, .capacity-pool ul { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-4); }.related li { display: grid; gap: var(--space-1); font-size: var(--text-sm); overflow-wrap: anywhere; }.related span { color: var(--text-tertiary); font-size: var(--text-xs); }.related strong { font-weight: var(--weight-medium); }
.capacity-pool { display: grid; gap: var(--space-3); font-size: var(--text-xs); }.capacity-pool + .capacity-pool { border-top: 1px solid var(--border-subtle); padding-top: var(--space-4); }.capacity-heading { display: flex; justify-content: space-between; gap: var(--space-2); flex-wrap: wrap; }.capacity-heading strong { font-weight: var(--weight-medium); }.capacity-heading span { color: var(--text-secondary); }.capacity-pool summary { cursor: pointer; color: var(--text-secondary); }.capacity-pool ul { gap: var(--space-2); margin-top: var(--space-3); line-height: 1.6; }
.launch-another { display: grid; gap: var(--space-2); justify-items: start; border-top: 1px solid var(--border-subtle); padding-top: var(--space-4); }.launch-another p { font-size: var(--text-xs); }
.loading { min-height: 240px; padding: var(--space-6); border: 1px solid var(--border-subtle); border-radius: var(--radius-lg); color: var(--text-secondary); }
@media (max-width: 1000px) { .detail-grid { grid-template-columns: minmax(0, 1fr); }.context-column { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) { .page { gap: var(--space-5); }.outcome { padding: var(--space-4); gap: var(--space-4); }.outcome h2 { font-size: var(--text-lg); }.outcome-message p { font-size: var(--text-sm); }.context-column { grid-template-columns: minmax(0, 1fr); }.technical-details > summary { padding: var(--space-4); }.technical-content { padding: 0 var(--space-4) var(--space-4); }.timing { gap: var(--space-4); }.timing > div:last-child { flex-basis: 100%; }.detail-grid { gap: var(--space-6); } }