Add live request pipeline recheck
Magent CI/CD / verify (push) Successful in 11m6s
Magent CI/CD / deploy-prod (push) Skipped
Magent CI/CD / deploy-beta (push) Successful in 1m56s

This commit is contained in:
2026-08-30 19:50:09 +12:00
parent 2cbd9fe73f
commit 02245d365e
5 changed files with 257 additions and 18 deletions
+10
View File
@@ -1993,6 +1993,16 @@ button:disabled,
font-size: 0.78rem;
font-weight: 750;
}
.request-action-row .request-recheck-button {
margin-left: auto;
border-color: var(--ops-line);
background: rgba(255, 255, 255, 0.035);
color: var(--ops-text);
}
.request-action-row .request-recheck-button:hover:not(:disabled) {
border-color: rgba(126, 215, 255, 0.48);
background: rgba(126, 215, 255, 0.09);
}
.request-action-feedback {
grid-column: 1 / -1;
padding: 13px 18px;
+48 -9
View File
@@ -427,6 +427,38 @@ export default function RequestTimelinePage() {
const posterUrl = snapshot.artwork?.poster_url
const resolvedPoster = posterUrl?.startsWith('http') ? posterUrl : posterUrl ? `${getApiBase()}${posterUrl}` : null
const recheckRequest = async () => {
setBusyAction('recheck_pipeline')
setActionError(null)
setActionMessage(null)
setReleaseOptions([])
try {
const response = await authFetch(
`${getApiBase()}/requests/${snapshot.request_id}/actions/recheck`,
{ method: 'POST' }
)
if (response.status === 401) {
clearToken()
router.push('/login')
return
}
if (!response.ok) {
throw new Error(await readApiError(response, 'The request could not be rechecked.'))
}
const data = await response.json()
if (!isSnapshotPayload(data?.snapshot)) {
throw new Error('The request was checked, but Magent did not return a valid pipeline.')
}
setSnapshot(data.snapshot)
setActionMessage(data?.message ?? 'Request status rebuilt from live service data.')
} catch (error) {
console.error(error)
setActionError(error instanceof Error ? error.message : 'The request could not be rechecked.')
} finally {
setBusyAction(null)
}
}
const runAction = async (action: RequestAction) => {
if (action.requires_confirmation && !window.confirm(`Run “${action.label}”?`)) return
const actionPaths: Record<string, string> = {
@@ -538,15 +570,22 @@ export default function RequestTimelinePage() {
<span className="request-overview-label">Next step</span>
<strong>{nextStep.title}</strong>
<p>{nextStep.description}</p>
{recommendedActions.length > 0 && (
<div className="request-action-row">
{recommendedActions.map((action) => (
<button key={action.id} type="button" disabled={Boolean(busyAction)} onClick={() => void runAction(action)}>
{busyAction === action.id ? 'Working…' : action.label}
</button>
))}
</div>
)}
<div className="request-action-row">
{recommendedActions.map((action) => (
<button key={action.id} type="button" disabled={Boolean(busyAction)} onClick={() => void runAction(action)}>
{busyAction === action.id ? 'Working…' : action.label}
</button>
))}
<button
type="button"
className="request-recheck-button"
disabled={Boolean(busyAction)}
onClick={() => void recheckRequest()}
title="Recheck Seerr, the library collector, qBittorrent, and the media server"
>
{busyAction === 'recheck_pipeline' ? 'Rechecking…' : 'Recheck request'}
</button>
</div>
</div>
{(actionMessage || actionError) && (
<div className={`request-action-feedback ${actionError ? 'is-error' : 'is-success'}`} role="status">