Show provisioning requesters and reserve Maxis for system actions

This commit is contained in:
2026-10-08 16:19:49 -04:00
parent 2b155ded8f
commit d8fb7e1d66
10 changed files with 77 additions and 15 deletions
+6 -4
View File
@@ -22,7 +22,7 @@
import { contextHref } from '$lib/navigation-context.js';
import { confirmAction } from '$ui/confirm.js';
import { serverTitle } from '$ui/server-labels.js';
import { elapsedTime } from '$ui/provisioning-presentation.js';
import { elapsedTime, provisioningRequester } from '$ui/provisioning-presentation.js';
import { provisioningQueueStatus, provisioningWarnings } from '$ui/provisioning-queue.js';
let lifecycleOpen = $state(false);
@@ -210,7 +210,7 @@
{#snippet operationTable(rows: Deployment[])}
<div class="table-scroll"><table>
<thead><tr><th scope="col">Server</th><th scope="col">Operation</th><th scope="col">Status</th><th scope="col">Source</th><th scope="col">Started</th><th scope="col" class="align-right">Details</th></tr></thead>
<thead><tr><th scope="col">Server</th><th scope="col">Operation</th><th scope="col">Status</th><th scope="col">Source</th><th scope="col">Requester</th><th scope="col">Started</th><th scope="col" class="align-right">Details</th></tr></thead>
<tbody>{#each rows as row (row.id)}
{@const status = provisioningQueueStatus(row)}
{@const primarySource = row.sources?.[0]}
@@ -221,14 +221,15 @@
<td><a href={operationHref}>{actionLabels[row.action]}</a></td>
<td><Badge variant={status.tone} size="md">{status.label}</Badge>{#if ['queued','waiting'].includes(status.group) && row.phaseStartedAt && now - Date.parse(row.phaseStartedAt) >= 600000}<small>In this stage {elapsedTime(row.phaseStartedAt, now)}</small>{/if}</td>
<td class="source-cell">{#if primarySource?.href}<a href={contextHref(primarySource.href, $page.url)}>{provisioningSourceLabel(row)}</a>{:else}<span>{provisioningSourceLabel(row)}</span>{/if}{#if (row.sources?.length ?? 0) > 1}<small>+{row.sources!.length - 1} more</small>{/if}</td>
<td class="requester-cell">{provisioningRequester(row)}</td>
<td><RelativeTime value={row.started_at} /></td>
<td class="align-right"><button class="text-button" aria-expanded={isExpanded} aria-controls={`operation-${row.id}`} aria-label={`${isExpanded ? 'Hide' : 'Show'} ${actionLabels[row.action].toLowerCase()} details for ${serverTitle(row.server)}`} onclick={() => expanded = { ...expanded, [row.id]: !isExpanded }}>{isExpanded ? 'Hide' : 'Details'} <span aria-hidden="true">{isExpanded ? '−' : '+'}</span></button></td>
</tr>
<tr hidden={!isExpanded} id={`operation-${row.id}`} class="detail-row"><td colspan="6">
<tr hidden={!isExpanded} id={`operation-${row.id}`} class="detail-row"><td colspan="7">
<div class="operation-details">
<p>{row.stage}</p>{#if row.error}<p class="error">{row.error}</p>{/if}
{#each provisioningWarnings(row.warnings) as warning}<p class="warning">{warning}</p>{/each}
<dl><div><dt>Started</dt><dd>{fmt(row.started_at)}</dd></div>{#if row.finished_at}<div><dt>Finished</dt><dd>{fmt(row.finished_at)}</dd></div>{/if}<div><dt>{row.finished_at ? 'Duration' : 'Elapsed'}</dt><dd>{elapsedTime(row.started_at, row.finished_at ? Date.parse(row.finished_at) : now)}</dd></div><div><dt>Operation ID</dt><dd class="mono">{row.id}</dd></div></dl>
<dl><div><dt>Requester</dt><dd>{provisioningRequester(row)}</dd></div><div><dt>Started</dt><dd>{fmt(row.started_at)}</dd></div>{#if row.finished_at}<div><dt>Finished</dt><dd>{fmt(row.finished_at)}</dd></div>{/if}<div><dt>{row.finished_at ? 'Duration' : 'Elapsed'}</dt><dd>{elapsedTime(row.started_at, row.finished_at ? Date.parse(row.finished_at) : now)}</dd></div><div><dt>Operation ID</dt><dd class="mono">{row.id}</dd></div></dl>
{#if row.sources?.length}<div class="detail-links">{#each row.sources as item}{#if item.href}<a href={contextHref(item.href, $page.url)}>{item.label}</a>{:else}<span class="muted">{item.label}</span>{/if}{/each}</div>{/if}
<div class="detail-links"><a href={operationHref}>Open operation</a>{#if row.server_exists && !row.server_deleted_at}<a href={contextHref(`/servers/${encodeURIComponent(row.server)}?tab=diagnostics`, $page.url)}>Diagnostics</a><a href={contextHref(`/servers/${encodeURIComponent(row.server)}?tab=logs`, $page.url)}>Open logs</a>{/if}{#if row.canCancel && !row.server_deleted_at}<Button variant="danger" size="sm" disabled={cancelling} onclick={() => cancelRequests([row])}>Cancel operation</Button>{/if}</div>
</div>
@@ -249,6 +250,7 @@
th { padding:10px 12px; color:var(--text-tertiary); font-size:var(--text-xs); font-weight:var(--weight-medium); border-bottom:1px solid var(--border-strong); }
td { padding:16px 12px; border-bottom:1px solid var(--border-subtle); vertical-align:middle; }tbody tr:hover { background:var(--surface); }
a { color:var(--accent-primary-hover); }.server-cell { min-width:160px; font-weight:var(--weight-semibold); }.source-cell { max-width:240px; overflow-wrap:anywhere; }
.requester-cell { max-width:180px; overflow-wrap:anywhere; }
small { display:block; margin-top:6px; color:var(--text-tertiary); font-size:var(--text-xs); }.align-right { text-align:right; }
.text-button { border:0; background:transparent; color:var(--text-secondary); font:inherit; padding:6px 0; cursor:pointer; white-space:nowrap; }
.detail-row { background:var(--surface); }.operation-details { display:grid; gap:16px; line-height:1.6; overflow-wrap:anywhere; }
+2 -2
View File
@@ -9,7 +9,7 @@
import { serverTitle } from '$ui/server-labels.js';
import { createProvisioningRefresh, type ProvisioningRefreshState } from '$ui/provisioning-refresh.js';
import { confirmAction } from '$ui/confirm.js';
import { elapsedTime, isProvisioningDetail, provisioningOutcome, provisioningReturn } from '$ui/provisioning-presentation.js';
import { elapsedTime, isProvisioningDetail, provisioningOutcome, provisioningRequester, provisioningReturn } from '$ui/provisioning-presentation.js';
import SectionHeader from '$ui/components/primitives/SectionHeader.svelte';
import Breadcrumbs from '$ui/components/primitives/Breadcrumbs.svelte';
import StatusBadge from '$ui/components/primitives/StatusBadge.svelte';
@@ -171,7 +171,7 @@
{/if}
<Card as="section" padding="md" ariaLabel="Operation details">
<div class="context-section"><h2>Operation details</h2><dl class="metadata">
<div><dt>Requested by</dt><dd>{deployment.requested_by ?? deployment.triggered_by}</dd></div>
<div><dt>Requester</dt><dd>{provisioningRequester(deployment)}</dd></div>
<div><dt>Requested at</dt><dd><RelativeTime value={deployment.started_at} /></dd></div>
<div><dt>Submission attempted</dt><dd><RelativeTime value={deployment.submitted_at} missing="Not recorded" /></dd></div>
<div><dt>Finished</dt><dd><RelativeTime value={deployment.finished_at} missing={outcome.active ? 'In progress' : 'Not recorded'} /></dd></div>