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,6 +121,151 @@ const RequestButton = ({
};
const buttons: ButtonOption[] = [];
// If there are pending requests, show request management options first
if (activeRequest || active4kRequest) {
if (
activeRequest &&
(activeRequest.requestedBy.id === user?.id ||
(activeRequests?.length === 1 &&
hasPermission(Permission.MANAGE_REQUESTS)))
) {
buttons.push({
id: 'active-request',
text: intl.formatMessage(messages.viewrequest),
action: () => {
setEditRequest(true);
setShowRequestModal(true);
},
svg: <InformationCircleIcon />,
});
}
if (
activeRequest &&
hasPermission(Permission.MANAGE_REQUESTS) &&
mediaType === 'movie'
) {
buttons.push(
{
id: 'approve-request',
text: intl.formatMessage(messages.approverequest),
action: () => {
modifyRequest(activeRequest, 'approve');
},
svg: <CheckIcon />,
},
{
id: 'decline-request',
text: intl.formatMessage(messages.declinerequest),
action: () => {
modifyRequest(activeRequest, 'decline');
},
svg: <XIcon />,
}
);
} else if (
activeRequests &&
activeRequests.length > 0 &&
hasPermission(Permission.MANAGE_REQUESTS) &&
mediaType === 'tv'
) {
buttons.push(
{
id: 'approve-request-batch',
text: intl.formatMessage(messages.approverequests, {
requestCount: activeRequests.length,
}),
action: () => {
modifyRequests(activeRequests, 'approve');
},
svg: <CheckIcon />,
},
{
id: 'decline-request-batch',
text: intl.formatMessage(messages.declinerequests, {
requestCount: activeRequests.length,
}),
action: () => {
modifyRequests(activeRequests, 'decline');
},
svg: <XIcon />,
}
);
}
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) &&
mediaType === 'movie'
) {
buttons.push(
{
id: 'approve-4k-request',
text: intl.formatMessage(messages.approverequest4k),
action: () => {
modifyRequest(active4kRequest, 'approve');
},
svg: <CheckIcon />,
},
{
id: 'decline-4k-request',
text: intl.formatMessage(messages.declinerequest4k),
action: () => {
modifyRequest(active4kRequest, 'decline');
},
svg: <XIcon />,
}
);
} else if (
active4kRequests &&
active4kRequests.length > 0 &&
hasPermission(Permission.MANAGE_REQUESTS) &&
mediaType === 'tv'
) {
buttons.push(
{
id: 'approve-4k-request-batch',
text: intl.formatMessage(messages.approve4krequests, {
requestCount: active4kRequests.length,
}),
action: () => {
modifyRequests(active4kRequests, 'approve');
},
svg: <CheckIcon />,
},
{
id: 'decline-4k-request-batch',
text: intl.formatMessage(messages.decline4krequests, {
requestCount: active4kRequests.length,
}),
action: () => {
modifyRequests(active4kRequests, 'decline');
},
svg: <XIcon />,
}
);
}
}
// Standard request button
if (
(!media || media.status === MediaStatus.UNKNOWN) &&
hasPermission(
@ -142,8 +287,29 @@ const RequestButton = ({
},
svg: <DownloadIcon />,
});
} else if (
mediaType === 'tv' &&
(!activeRequest || activeRequest.requestedBy.id !== user?.id) &&
hasPermission([Permission.REQUEST, Permission.REQUEST_TV], {
type: 'or',
}) &&
media &&
media.status !== MediaStatus.AVAILABLE &&
media.status !== MediaStatus.UNKNOWN &&
!isShowComplete
) {
buttons.push({
id: 'request-more',
text: intl.formatMessage(messages.requestmore),
action: () => {
setEditRequest(false);
setShowRequestModal(true);
},
svg: <DownloadIcon />,
});
}
// 4K request button
if (
(!media || media.status4k === MediaStatus.UNKNOWN) &&
hasPermission(
@ -167,175 +333,7 @@ const RequestButton = ({
},
svg: <DownloadIcon />,
});
}
if (
activeRequest &&
(activeRequest.requestedBy.id === user?.id ||
(activeRequests?.length === 1 &&
hasPermission(Permission.MANAGE_REQUESTS)))
) {
buttons.push({
id: 'active-request',
text: intl.formatMessage(messages.viewrequest),
action: () => {
setEditRequest(true);
setShowRequestModal(true);
},
svg: <InformationCircleIcon />,
});
}
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) &&
mediaType === 'movie'
) {
buttons.push(
{
id: 'approve-request',
text: intl.formatMessage(messages.approverequest),
action: () => {
modifyRequest(activeRequest, 'approve');
},
svg: <CheckIcon />,
},
{
id: 'decline-request',
text: intl.formatMessage(messages.declinerequest),
action: () => {
modifyRequest(activeRequest, 'decline');
},
svg: <XIcon />,
}
);
}
if (
activeRequests &&
activeRequests.length > 0 &&
hasPermission(Permission.MANAGE_REQUESTS) &&
mediaType === 'tv'
) {
buttons.push(
{
id: 'approve-request-batch',
text: intl.formatMessage(messages.approverequests, {
requestCount: activeRequests.length,
}),
action: () => {
modifyRequests(activeRequests, 'approve');
},
svg: <CheckIcon />,
},
{
id: 'decline-request-batch',
text: intl.formatMessage(messages.declinerequests, {
requestCount: activeRequests.length,
}),
action: () => {
modifyRequests(activeRequests, 'decline');
},
svg: <XIcon />,
}
);
}
if (
active4kRequest &&
hasPermission(Permission.MANAGE_REQUESTS) &&
mediaType === 'movie'
) {
buttons.push(
{
id: 'approve-4k-request',
text: intl.formatMessage(messages.approverequest4k),
action: () => {
modifyRequest(active4kRequest, 'approve');
},
svg: <CheckIcon />,
},
{
id: 'decline-4k-request',
text: intl.formatMessage(messages.declinerequest4k),
action: () => {
modifyRequest(active4kRequest, 'decline');
},
svg: <XIcon />,
}
);
}
if (
active4kRequests &&
active4kRequests.length > 0 &&
hasPermission(Permission.MANAGE_REQUESTS) &&
mediaType === 'tv'
) {
buttons.push(
{
id: 'approve-4k-request-batch',
text: intl.formatMessage(messages.approve4krequests, {
requestCount: active4kRequests.length,
}),
action: () => {
modifyRequests(active4kRequests, 'approve');
},
svg: <CheckIcon />,
},
{
id: 'decline-4k-request-batch',
text: intl.formatMessage(messages.decline4krequests, {
requestCount: active4kRequests.length,
}),
action: () => {
modifyRequests(active4kRequests, 'decline');
},
svg: <XIcon />,
}
);
}
if (
mediaType === 'tv' &&
(!activeRequest || activeRequest.requestedBy.id !== user?.id) &&
hasPermission([Permission.REQUEST, Permission.REQUEST_TV], {
type: 'or',
}) &&
media &&
media.status !== MediaStatus.AVAILABLE &&
media.status !== MediaStatus.UNKNOWN &&
!isShowComplete
) {
buttons.push({
id: 'request-more',
text: intl.formatMessage(messages.requestmore),
action: () => {
setEditRequest(false);
setShowRequestModal(true);
},
svg: <DownloadIcon />,
});
}
if (
} 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