fix: better ordering of RequestButton options & properly handle failed requests (#2944)

* fix: better ordering of RequestButton options & properly handle failed requests

* fix: appease prettier
pull/2944/merge
TheCatLady 2 years ago committed by GitHub
parent e5d8c93ab8
commit c143c0b8d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -4430,7 +4430,16 @@ paths:
schema:
type: string
nullable: true
enum: [all, approved, available, pending, processing, unavailable]
enum:
[
all,
approved,
available,
pending,
processing,
unavailable,
failed,
]
- in: query
name: sort
schema:

@ -2,6 +2,7 @@ export enum MediaRequestStatus {
PENDING = 1,
APPROVED,
DECLINED,
FAILED,
}
export enum MediaType {

@ -451,10 +451,13 @@ export class MediaRequest {
await mediaRepository.save(media);
})
.catch(async () => {
media[this.is4k ? 'status4k' : 'status'] = MediaStatus.UNKNOWN;
await mediaRepository.save(media);
const requestRepository = getRepository(MediaRequest);
this.status = MediaRequestStatus.FAILED;
requestRepository.save(this);
logger.warn(
'Something went wrong sending movie request to Radarr, marking status as UNKNOWN',
'Something went wrong sending movie request to Radarr, marking status as FAILED',
{
label: 'Media Request',
requestId: this.id,
@ -684,10 +687,13 @@ export class MediaRequest {
await mediaRepository.save(media);
})
.catch(async () => {
media[this.is4k ? 'status4k' : 'status'] = MediaStatus.UNKNOWN;
await mediaRepository.save(media);
const requestRepository = getRepository(MediaRequest);
this.status = MediaRequestStatus.FAILED;
requestRepository.save(this);
logger.warn(
'Something went wrong sending series request to Sonarr, marking status as UNKNOWN',
'Something went wrong sending series request to Sonarr, marking status as FAILED',
{
label: 'Media Request',
requestId: this.id,

@ -40,11 +40,15 @@ requestRoutes.get<Record<string, unknown>, RequestResultsResponse>(
MediaRequestStatus.APPROVED,
];
break;
case 'failed':
statusFilter = [MediaRequestStatus.FAILED];
break;
default:
statusFilter = [
MediaRequestStatus.PENDING,
MediaRequestStatus.APPROVED,
MediaRequestStatus.DECLINED,
MediaRequestStatus.FAILED,
];
}

@ -179,6 +179,11 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
{intl.formatMessage(globalMessages.pending)}
</Badge>
)}
{request.status === MediaRequestStatus.FAILED && (
<Badge badgeType="danger">
{intl.formatMessage(globalMessages.failed)}
</Badge>
)}
</div>
</div>
<div className="mt-2 flex items-center text-sm leading-5 sm:mt-0">

@ -77,13 +77,13 @@ const RequestButton = ({
(request) => request.status === MediaRequestStatus.PENDING && request.is4k
);
// Current user's pending request, or the first pending request
const activeRequest = useMemo(() => {
return activeRequests && activeRequests.length > 0
? activeRequests.find((request) => request.requestedBy.id === user?.id) ??
activeRequests[0]
: undefined;
}, [activeRequests, user]);
const active4kRequest = useMemo(() => {
return active4kRequests && active4kRequests.length > 0
? active4kRequests.find(
@ -121,54 +121,9 @@ const RequestButton = ({
};
const buttons: ButtonOption[] = [];
if (
(!media || media.status === MediaStatus.UNKNOWN) &&
hasPermission(
[
Permission.REQUEST,
mediaType === 'movie'
? Permission.REQUEST_MOVIE
: Permission.REQUEST_TV,
],
{ type: 'or' }
)
) {
buttons.push({
id: 'request',
text: intl.formatMessage(globalMessages.request),
action: () => {
setEditRequest(false);
setShowRequestModal(true);
},
svg: <DownloadIcon />,
});
}
if (
(!media || media.status4k === MediaStatus.UNKNOWN) &&
hasPermission(
[
Permission.REQUEST_4K,
mediaType === 'movie'
? Permission.REQUEST_4K_MOVIE
: Permission.REQUEST_4K_TV,
],
{ type: 'or' }
) &&
((settings.currentSettings.movie4kEnabled && mediaType === 'movie') ||
(settings.currentSettings.series4kEnabled && mediaType === 'tv'))
) {
buttons.push({
id: 'request4k',
text: intl.formatMessage(globalMessages.request4k),
action: () => {
setEditRequest(false);
setShowRequest4kModal(true);
},
svg: <DownloadIcon />,
});
}
// If there are pending requests, show request management options first
if (activeRequest || active4kRequest) {
if (
activeRequest &&
(activeRequest.requestedBy.id === user?.id ||
@ -186,23 +141,6 @@ const RequestButton = ({
});
}
if (
active4kRequest &&
(active4kRequest.requestedBy.id === user?.id ||
(active4kRequests?.length === 1 &&
hasPermission(Permission.MANAGE_REQUESTS)))
) {
buttons.push({
id: 'active-4k-request',
text: intl.formatMessage(messages.viewrequest4k),
action: () => {
setEditRequest(true);
setShowRequest4kModal(true);
},
svg: <InformationCircleIcon />,
});
}
if (
activeRequest &&
hasPermission(Permission.MANAGE_REQUESTS) &&
@ -226,9 +164,7 @@ const RequestButton = ({
svg: <XIcon />,
}
);
}
if (
} else if (
activeRequests &&
activeRequests.length > 0 &&
hasPermission(Permission.MANAGE_REQUESTS) &&
@ -258,6 +194,23 @@ const RequestButton = ({
);
}
if (
active4kRequest &&
(active4kRequest.requestedBy.id === user?.id ||
(active4kRequests?.length === 1 &&
hasPermission(Permission.MANAGE_REQUESTS)))
) {
buttons.push({
id: 'active-4k-request',
text: intl.formatMessage(messages.viewrequest4k),
action: () => {
setEditRequest(true);
setShowRequest4kModal(true);
},
svg: <InformationCircleIcon />,
});
}
if (
active4kRequest &&
hasPermission(Permission.MANAGE_REQUESTS) &&
@ -281,9 +234,7 @@ const RequestButton = ({
svg: <XIcon />,
}
);
}
if (
} else if (
active4kRequests &&
active4kRequests.length > 0 &&
hasPermission(Permission.MANAGE_REQUESTS) &&
@ -312,8 +263,31 @@ const RequestButton = ({
}
);
}
}
// Standard request button
if (
(!media || media.status === MediaStatus.UNKNOWN) &&
hasPermission(
[
Permission.REQUEST,
mediaType === 'movie'
? Permission.REQUEST_MOVIE
: Permission.REQUEST_TV,
],
{ type: 'or' }
)
) {
buttons.push({
id: 'request',
text: intl.formatMessage(globalMessages.request),
action: () => {
setEditRequest(false);
setShowRequestModal(true);
},
svg: <DownloadIcon />,
});
} else if (
mediaType === 'tv' &&
(!activeRequest || activeRequest.requestedBy.id !== user?.id) &&
hasPermission([Permission.REQUEST, Permission.REQUEST_TV], {
@ -335,7 +309,31 @@ const RequestButton = ({
});
}
// 4K request button
if (
(!media || media.status4k === MediaStatus.UNKNOWN) &&
hasPermission(
[
Permission.REQUEST_4K,
mediaType === 'movie'
? Permission.REQUEST_4K_MOVIE
: Permission.REQUEST_4K_TV,
],
{ type: 'or' }
) &&
((settings.currentSettings.movie4kEnabled && mediaType === 'movie') ||
(settings.currentSettings.series4kEnabled && mediaType === 'tv'))
) {
buttons.push({
id: 'request4k',
text: intl.formatMessage(globalMessages.request4k),
action: () => {
setEditRequest(false);
setShowRequest4kModal(true);
},
svg: <DownloadIcon />,
});
} else if (
mediaType === 'tv' &&
(!active4kRequest || active4kRequest.requestedBy.id !== user?.id) &&
hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_TV], {

@ -12,10 +12,7 @@ import { useInView } from 'react-intersection-observer';
import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR, { mutate } from 'swr';
import {
MediaRequestStatus,
MediaStatus,
} from '../../../server/constants/media';
import { MediaRequestStatus } from '../../../server/constants/media';
import type { MediaRequest } from '../../../server/entity/MediaRequest';
import type { MovieDetails } from '../../../server/models/Movie';
import type { TvDetails } from '../../../server/models/Tv';
@ -275,8 +272,7 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
<Badge badgeType="danger">
{intl.formatMessage(globalMessages.declined)}
</Badge>
) : requestData.media[requestData.is4k ? 'status4k' : 'status'] ===
MediaStatus.UNKNOWN ? (
) : requestData.status === MediaRequestStatus.FAILED ? (
<Badge
badgeType="danger"
href={`/${requestData.type}/${requestData.media.tmdbId}?manage=1`}
@ -305,9 +301,7 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
)}
</div>
<div className="flex flex-1 items-end space-x-2">
{requestData.media[requestData.is4k ? 'status4k' : 'status'] ===
MediaStatus.UNKNOWN &&
requestData.status !== MediaRequestStatus.DECLINED &&
{requestData.status === MediaRequestStatus.FAILED &&
hasPermission(Permission.MANAGE_REQUESTS) && (
<Button
buttonType="primary"

@ -12,10 +12,7 @@ import { useInView } from 'react-intersection-observer';
import { defineMessages, FormattedRelativeTime, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
import {
MediaRequestStatus,
MediaStatus,
} from '../../../../server/constants/media';
import { MediaRequestStatus } from '../../../../server/constants/media';
import type { MediaRequest } from '../../../../server/entity/MediaRequest';
import type { MovieDetails } from '../../../../server/models/Movie';
import type { TvDetails } from '../../../../server/models/Tv';
@ -273,9 +270,7 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
<Badge badgeType="danger">
{intl.formatMessage(globalMessages.declined)}
</Badge>
) : requestData.media[
requestData.is4k ? 'status4k' : 'status'
] === MediaStatus.UNKNOWN ? (
) : requestData.status === MediaRequestStatus.FAILED ? (
<Badge
badgeType="danger"
href={`/${requestData.type}/${requestData.media.tmdbId}?manage=1`}
@ -402,9 +397,7 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
</div>
</div>
<div className="z-10 mt-4 flex w-full flex-col justify-center space-y-2 pl-4 pr-4 xl:mt-0 xl:w-96 xl:items-end xl:pl-0">
{requestData.media[requestData.is4k ? 'status4k' : 'status'] ===
MediaStatus.UNKNOWN &&
requestData.status !== MediaRequestStatus.DECLINED &&
{requestData.status === MediaRequestStatus.FAILED &&
hasPermission(Permission.MANAGE_REQUESTS) && (
<Button
className="w-full"

@ -33,6 +33,7 @@ enum Filter {
PROCESSING = 'processing',
AVAILABLE = 'available',
UNAVAILABLE = 'unavailable',
FAILED = 'failed',
}
type Sort = 'added' | 'modified';
@ -158,6 +159,9 @@ const RequestList = () => {
<option value="processing">
{intl.formatMessage(globalMessages.processing)}
</option>
<option value="failed">
{intl.formatMessage(globalMessages.failed)}
</option>
<option value="available">
{intl.formatMessage(globalMessages.available)}
</option>

Loading…
Cancel
Save