Merge pull request #226 from builderz-labs/fix/issue-215-workspace-pending-state
fix(workspaces): unblock pending tenant bootstrap flow
This commit is contained in:
commit
008bba4afb
|
|
@ -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) => {
|
const openDecommissionDialog = (tenant: TenantRow) => {
|
||||||
setOpenActionMenu(null)
|
setOpenActionMenu(null)
|
||||||
setDecommissionDialog({
|
setDecommissionDialog({
|
||||||
|
|
@ -884,11 +912,11 @@ export function SuperAdminPanel() {
|
||||||
View events
|
View events
|
||||||
</button>
|
</button>
|
||||||
<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)}
|
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"
|
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>
|
||||||
<button
|
<button
|
||||||
onClick={() => setJobState(job.id, 'reject')}
|
onClick={() => setJobState(job.id, 'reject')}
|
||||||
|
|
|
||||||
|
|
@ -817,9 +817,14 @@ export async function executeProvisionJob(jobId: number, actor: string) {
|
||||||
jobId,
|
jobId,
|
||||||
)
|
)
|
||||||
|
|
||||||
const completedTenantStatus = dryRun
|
const completedTenantStatus = (() => {
|
||||||
? previousTenantStatus
|
if (jobType === 'decommission') {
|
||||||
: (jobType === 'decommission' ? 'suspended' : 'active')
|
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(`
|
db.prepare(`
|
||||||
UPDATE tenants
|
UPDATE tenants
|
||||||
SET status = ?, updated_at = (unixepoch())
|
SET status = ?, updated_at = (unixepoch())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue