Show live repair progress on requests
Magent CI/CD / verify (push) Canceled after 4m53s
Magent CI/CD / deploy-prod (push) Canceled after 0s
Magent CI/CD / deploy-beta (push) Canceled after 0s

This commit is contained in:
2026-09-01 21:17:50 +12:00
parent 6391fbfd81
commit 3fc52f70c7
5 changed files with 469 additions and 5 deletions
+58 -2
View File
@@ -36,6 +36,24 @@ type PipelineStage = {
link?: string | null
}
type RepairActivityStep = {
id: string
label: string
state: 'complete' | 'active' | 'attention' | 'waiting' | string
detail: string
}
type RepairActivity = {
visible?: boolean
actionId?: string
state?: 'searching' | 'downloading' | 'importing' | 'indexing' | 'complete' | 'attention' | string
headline?: string
message?: string
service?: string
updatedAt?: string | null
steps?: RepairActivityStep[]
}
type Snapshot = {
request_id: string
title: string
@@ -57,6 +75,7 @@ type Snapshot = {
}
nextStep?: { title?: string; description?: string; actionIds?: string[] }
pipeline?: PipelineStage[]
repairActivity?: RepairActivity
}
raw?: Record<string, any>
}
@@ -288,6 +307,10 @@ export default function RequestTimelinePage() {
(stage) => stage.id === 'available' && stage.state === 'active'
)
)
const repairIsActive = Boolean(
snapshot?.presentation?.repairActivity?.visible &&
!['complete', 'attention'].includes(snapshot.presentation.repairActivity.state ?? '')
)
useEffect(() => {
if (!requestId) return
@@ -367,12 +390,15 @@ export default function RequestTimelinePage() {
if (!stopped) console.error(error)
}
}
const timer = window.setInterval(() => void refresh(), awaitingMediaIndex ? 5_000 : 15_000)
const timer = window.setInterval(
() => void refresh(),
awaitingMediaIndex || repairIsActive ? 5_000 : 15_000,
)
return () => {
stopped = true
window.clearInterval(timer)
}
}, [awaitingMediaIndex, requestId, router])
}, [awaitingMediaIndex, repairIsActive, requestId, router])
const liveDownloadKey = useMemo(() => {
const downloadStage = snapshot?.presentation?.pipeline?.find((stage) => stage.id === 'download')
@@ -470,6 +496,7 @@ export default function RequestTimelinePage() {
const statusLabel = presentation.status?.label ?? fallbackStatusLabel(snapshot.state)
const statusMeaning = presentation.status?.meaning ?? snapshot.state_reason ?? 'Magent is checking this request.'
const download = presentation.download
const repairActivity = presentation.repairActivity
const downloadVisible = Boolean(download?.visible)
const nextStep = presentation.nextStep ?? {
title: snapshot.actions[0]?.label ?? 'No action needed right now',
@@ -753,6 +780,35 @@ export default function RequestTimelinePage() {
)}
</section>
{repairActivity?.visible && (
<section className={`request-repair-activity is-${repairActivity.state ?? 'searching'}`} aria-live="polite">
<div className="request-repair-heading">
<div>
<span className="section-kicker">Repair activity</span>
<h2>{repairActivity.headline ?? 'Repair in progress'}</h2>
<p>{repairActivity.message ?? 'Magent is checking the repair with the connected services.'}</p>
</div>
<div className="request-repair-meta">
<span className={`request-operation-status is-${repairActivity.state === 'attention' ? 'error' : repairActivity.state === 'complete' ? 'complete' : 'running'}`}>
{repairActivity.state === 'complete' ? 'Complete' : repairActivity.state === 'attention' ? 'Attention' : 'Live'}
</span>
{repairActivity.updatedAt && <small>Updated {formatWhen(repairActivity.updatedAt)}</small>}
</div>
</div>
<div className="request-repair-steps">
{(repairActivity.steps ?? []).map((step) => (
<div className={`request-repair-step is-${step.state}`} key={step.id}>
<i aria-hidden="true" />
<div>
<strong>{step.label}</strong>
<span>{step.detail}</span>
</div>
</div>
))}
</div>
</section>
)}
<section className="request-journey" aria-labelledby="request-journey-heading">
<div className="request-journey-heading">
<div>