fix(workspaces): unblock pending tenant bootstrap flow

This commit is contained in:
Nyk 2026-03-05 19:26:43 +07:00
parent 3877d0b345
commit b93d885ad1
2 changed files with 38 additions and 5 deletions

View File

@ -395,6 +395,34 @@ export function SuperAdminPanel() {
}
}
const approveAndRunJob = async (jobId: number) => {
setBusyJobId(jobId)
try {
const approveRes = await fetch(`/api/super/provision-jobs/${jobId}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'approve' }),
})
const approveJson = await approveRes.json().catch(() => ({}))
if (!approveRes.ok) throw new Error(approveJson?.error || `Failed to approve job #${jobId}`)
const runRes = await fetch(`/api/super/provision-jobs/${jobId}/run`, { method: 'POST' })
const runJson = await runRes.json().catch(() => ({}))
if (!runRes.ok) throw new Error(runJson?.error || `Failed to run job #${jobId}`)
showFeedback(true, `Job #${jobId} approved and executed`)
await load()
await loadJobDetail(jobId)
} catch (e: any) {
showFeedback(false, e?.message || `Failed to approve/run job #${jobId}`)
await load()
await loadJobDetail(jobId)
} finally {
setBusyJobId(null)
setOpenActionMenu(null)
}
}
const openDecommissionDialog = (tenant: TenantRow) => {
setOpenActionMenu(null)
setDecommissionDialog({
@ -884,11 +912,11 @@ export function SuperAdminPanel() {
View events
</button>
<button
onClick={() => setJobState(job.id, 'approve')}
onClick={() => Number(job.dry_run) === 1 ? approveAndRunJob(job.id) : setJobState(job.id, 'approve')}
disabled={busyJobId === job.id || !['queued', 'rejected', 'failed'].includes(job.status)}
className="w-full px-3 py-2 text-xs text-emerald-400 hover:bg-emerald-500/10 disabled:opacity-40"
>
Approve
{Number(job.dry_run) === 1 ? 'Approve + Run' : 'Approve'}
</button>
<button
onClick={() => setJobState(job.id, 'reject')}

View File

@ -817,9 +817,14 @@ export async function executeProvisionJob(jobId: number, actor: string) {
jobId,
)
const completedTenantStatus = dryRun
? previousTenantStatus
: (jobType === 'decommission' ? 'suspended' : 'active')
const completedTenantStatus = (() => {
if (jobType === 'decommission') {
return dryRun ? previousTenantStatus : 'suspended'
}
// For bootstrap/update jobs, mark tenant active when the workflow completes,
// even in dry-run mode, so workspace lifecycle is not stuck in pending.
return 'active'
})()
db.prepare(`
UPDATE tenants
SET status = ?, updated_at = (unixepoch())