feat: simplify ready requests and add global search
This commit is contained in:
@@ -4,11 +4,13 @@ import PageHeading from '../../ui/PageHeading'
|
||||
import RequestLanguage from './RequestLanguage'
|
||||
import { lockBodyScroll } from '../../lib/scrollLock'
|
||||
import LatestActivity from './LatestActivity'
|
||||
import RequestIssueDialog from './RequestIssueDialog'
|
||||
|
||||
import Image from 'next/image'
|
||||
import { useParams, useRouter } from 'next/navigation'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { authFetch, clearToken, getApiBase, getToken } from '../../lib/auth'
|
||||
import { canAccess } from '../../lib/features'
|
||||
|
||||
type TimelineHop = {
|
||||
service: string
|
||||
@@ -325,6 +327,7 @@ export default function RequestTimelinePage() {
|
||||
const [historyActions, setHistoryActions] = useState<ActionHistory[]>([])
|
||||
const [operationProgress, setOperationProgress] = useState<OperationProgress | null>(null)
|
||||
const [isAdmin, setIsAdmin] = useState(false)
|
||||
const [canReportIssues, setCanReportIssues] = useState(false)
|
||||
const awaitingMediaIndex = Boolean(
|
||||
snapshot?.presentation?.pipeline?.some(
|
||||
(stage) => stage.id === 'available' && stage.state === 'active'
|
||||
@@ -386,6 +389,7 @@ export default function RequestTimelinePage() {
|
||||
const me = await meResponse.json()
|
||||
const viewerIsAdmin = me?.role === 'admin'
|
||||
setIsAdmin(viewerIsAdmin)
|
||||
setCanReportIssues(canAccess(me, 'issues'))
|
||||
if (!snapshotResponse.ok) {
|
||||
throw new Error(await readApiError(snapshotResponse, 'Unable to load this request.'))
|
||||
}
|
||||
@@ -537,6 +541,7 @@ export default function RequestTimelinePage() {
|
||||
const mediaServerLink = availableStage?.state === 'complete' && availableStage.link
|
||||
? availableStage.link
|
||||
: null
|
||||
const requestComplete = ['COMPLETED', 'AVAILABLE'].includes(snapshot.state) || availableStage?.state === 'complete'
|
||||
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
|
||||
@@ -815,40 +820,39 @@ export default function RequestTimelinePage() {
|
||||
</div>
|
||||
)}
|
||||
{operationProgress && <LatestActivity operation={operationProgress} besideDownload={downloadVisible} onDismiss={() => setOperationProgress(null)} />}
|
||||
<div className="request-overview-block request-next-step">
|
||||
<div className="request-next-step-main">
|
||||
<div className="request-next-step-copy">
|
||||
<span className="request-overview-label">Next step</span>
|
||||
<strong>{nextStep.title}</strong>
|
||||
<p>{nextStep.description}</p>
|
||||
<div className={`request-overview-block request-next-step ${requestComplete ? 'is-ready' : ''}`}>
|
||||
{requestComplete ? (
|
||||
<div className="request-ready-actions">
|
||||
<section>
|
||||
<span className="request-overview-label">Ready to watch</span>
|
||||
<strong>Watch this now!</strong>
|
||||
<p>Open {snapshot.title} directly in Grizzlyflix.</p>
|
||||
{mediaServerLink ? <a className="request-watch-button" href={mediaServerLink} target="_blank" rel="noreferrer">Watch on Grizzlyflix <span aria-hidden="true">→</span></a> : <span className="request-ready-unavailable">The Grizzlyflix watch link is not configured.</span>}
|
||||
</section>
|
||||
<section>
|
||||
<span className="request-overview-label">Need help?</span>
|
||||
<strong>Is there a problem with this?</strong>
|
||||
<p>Let us know what is wrong and we'll attach the title and request details automatically.</p>
|
||||
{canReportIssues ? <RequestIssueDialog requestId={snapshot.request_id} title={snapshot.title} year={snapshot.year} requestType={snapshot.request_type} /> : <span className="request-ready-unavailable">Issue reporting is not enabled for your account.</span>}
|
||||
</section>
|
||||
</div>
|
||||
{mediaServerLink && (
|
||||
<a
|
||||
className="request-watch-button"
|
||||
href={mediaServerLink}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
Watch on Grizzlyflix <span aria-hidden="true">→</span>
|
||||
</a>
|
||||
)}
|
||||
</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 className="request-next-step-main">
|
||||
<div className="request-next-step-copy">
|
||||
<span className="request-overview-label">Next step</span>
|
||||
<strong>{nextStep.title}</strong>
|
||||
<p>{nextStep.description}</p>
|
||||
</div>
|
||||
</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">
|
||||
@@ -886,7 +890,7 @@ export default function RequestTimelinePage() {
|
||||
</section>
|
||||
)}
|
||||
|
||||
<section className="request-journey" aria-labelledby="request-journey-heading">
|
||||
{!requestComplete && <section className="request-journey" aria-labelledby="request-journey-heading">
|
||||
<div className="request-journey-heading">
|
||||
<div>
|
||||
<span className="section-kicker">Live collection path</span>
|
||||
@@ -975,7 +979,7 @@ export default function RequestTimelinePage() {
|
||||
})}
|
||||
</div>
|
||||
|
||||
</section>
|
||||
</section>}
|
||||
|
||||
{releasePickerOpen && (
|
||||
<div className="request-release-modal-layer">
|
||||
|
||||
Reference in New Issue
Block a user