diff --git a/docs/guides/provisioning.md b/docs/guides/provisioning.md index 9cdf931..43d50ed 100644 --- a/docs/guides/provisioning.md +++ b/docs/guides/provisioning.md @@ -211,12 +211,12 @@ Uncertain inspections keep it waiting; the old command is never replayed merely because its receipt was lost. Create and rebuild capture a setup when queued and select the latest promoted -files again when creation begins. The page distinguishes **Setup captured when -queued** from **Files selected for this attempt**. A queued capture does not pin -versions; an attempted selection is not proof that every file was installed. -**Launch another server** opens the creation dialog with the recorded game and -map as editable starting values. It checks the latest promoted setup and creates -a separate server with a fresh identity and port. +files again when creation begins. The **Launch files** card shows one selection +status beside the capture time: **Captured when queued**, **Selected when creation +began**, or **Recorded setup; selection time unknown** for older records. A queued +capture does not pin versions; an attempted selection is not proof that every +file was installed. Expand the managed file list to inspect versions, paths, +checksums, and the recipe fingerprint. ### History and refresh behavior diff --git a/src/lib/ui/components/LaunchRecipe.svelte b/src/lib/ui/components/LaunchRecipe.svelte index 9bd8dc5..bbc12a4 100644 --- a/src/lib/ui/components/LaunchRecipe.svelte +++ b/src/lib/ui/components/LaunchRecipe.svelte @@ -1,11 +1,11 @@
-
{historical ? selectionStatus === 'queued' ? 'Queued setup capture' : selectionStatus === 'attempted' ? 'Selected for this attempt' : 'Recorded launch files' : 'Current promoted setup'}

{recipe.mapName}

{recipe.game === 't6' ? 'Black Ops II' : 'Black Ops I'}
+
{#if !historical}Current promoted setup{/if}

{recipe.mapName}

{recipe.game === 't6' ? 'Black Ops II' : 'Black Ops I'}
Configuration
{recipe.configSource}
Container image
{recipe.image}
@@ -14,7 +14,7 @@
{recipe.files.length} managed file{recipe.files.length === 1 ? '' : 's'} {historical ? 'recorded for this deployment' : 'in the current setup'}
    {#each recipe.files as file}
  • {file.name}{file.version !== null ? `v${file.version}` : 'Generated'} · {file.kind} · {file.size.toLocaleString()} bytes
    {file.path}SHA-256 {file.sha256.slice(0, 12)}
  • {/each}
-

{historical ? 'Recorded' : 'Previewed'} . {historical ? selectionStatus === 'queued' ? 'Versions are selected again when creation begins. This queued capture does not pin them.' : selectionStatus === 'attempted' ? 'These files were selected for this attempt; this does not confirm installation succeeded. Launch again uses the latest promoted setup.' : 'This records the saved setup for this deployment. Launch again uses the latest promoted setup for this map.' : 'This preview shows the promoted setup at the time above. The deployment history records the files selected when provisioning begins.'}

+ {#if !historical}

Previewed . This preview shows the promoted setup at the time above. The deployment history records the files selected when provisioning begins.

{/if} Recipe {recipe.fingerprint.slice(0, 16)}
diff --git a/src/routes/provisioning/[id]/+page.svelte b/src/routes/provisioning/[id]/+page.svelte index c6318ef..1dd4bd6 100644 --- a/src/routes/provisioning/[id]/+page.svelte +++ b/src/routes/provisioning/[id]/+page.svelte @@ -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({ 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}
Current slot holders
{/if} {/each}

Capacity snapshot

{/if} -

{recipeHeading}

+

Launch files

{#if detail.recipe} {#if detail.blueprintName}

From {detail.blueprintName}

{/if} -

{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.'}

-

Captured {@render dateTime(detail.recipe.capturedAt)}

- -

Creates a separate server with a fresh ID and port using the latest promoted files. It does not repair this instance.

+

{recipeSelection} ·

+ {:else}

{['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.'}

{/if}
@@ -212,7 +207,6 @@
- {#if detail.recipe}{/if} {/key} {:else}
Loading provisioning operation…
{/if} @@ -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); } }