mirror of
https://github.com/sct/overseerr.git
synced 2025-09-17 17:24:35 +02:00
fix: set editRequest attribute as necessary, allow users to edit their own pending requests, and show 'View Request' button on series pages (#1446)
* fix: set editRequest attribute for RequestModal * fix: remove now-unneeded conditional * fix(ui): only show 'View Request' for user's own requests if they don't have MANAGE_REQUESTS perm * fix(ui): show edit button on request list for own requests & 'View Request' button on series pages * fix(ui): do not show 'Request More' if user already has a pending request * fix: address PR comments * fix(lang): edit usercreatedfaileexisting string & generate translation key * fix: users should always be able to view/edit their own requests even if their perms have changed also fixed capitalization of 'Signing In...' string
This commit is contained in:
@@ -493,7 +493,6 @@ requestRoutes.get('/:requestId', async (req, res, next) => {
|
|||||||
|
|
||||||
requestRoutes.put<{ requestId: string }>(
|
requestRoutes.put<{ requestId: string }>(
|
||||||
'/:requestId',
|
'/:requestId',
|
||||||
isAuthenticated(Permission.MANAGE_REQUESTS),
|
|
||||||
async (req, res, next) => {
|
async (req, res, next) => {
|
||||||
const requestRepository = getRepository(MediaRequest);
|
const requestRepository = getRepository(MediaRequest);
|
||||||
const userRepository = getRepository(User);
|
const userRepository = getRepository(User);
|
||||||
@@ -503,17 +502,30 @@ requestRoutes.put<{ requestId: string }>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (!request) {
|
if (!request) {
|
||||||
return next({ status: 404, message: 'Request not found' });
|
return next({ status: 404, message: 'Request not found.' });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(request.requestedBy.id !== req.user?.id ||
|
||||||
|
(req.body.mediaType !== 'tv' &&
|
||||||
|
!req.user?.hasPermission(Permission.REQUEST_ADVANCED))) &&
|
||||||
|
!req.user?.hasPermission(Permission.MANAGE_REQUESTS)
|
||||||
|
) {
|
||||||
|
return next({
|
||||||
|
status: 403,
|
||||||
|
message: 'You do not have permission to modify this request.',
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let requestUser = req.user;
|
let requestUser = req.user;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
req.body.userId &&
|
req.body.userId &&
|
||||||
!(
|
req.body.userId !== req.user?.id &&
|
||||||
req.user?.hasPermission(Permission.MANAGE_USERS) &&
|
!req.user?.hasPermission([
|
||||||
req.user?.hasPermission(Permission.MANAGE_REQUESTS)
|
Permission.MANAGE_USERS,
|
||||||
)
|
Permission.MANAGE_REQUESTS,
|
||||||
|
])
|
||||||
) {
|
) {
|
||||||
return next({
|
return next({
|
||||||
status: 403,
|
status: 403,
|
||||||
@@ -546,7 +558,7 @@ requestRoutes.put<{ requestId: string }>(
|
|||||||
|
|
||||||
if (!requestedSeasons || requestedSeasons.length === 0) {
|
if (!requestedSeasons || requestedSeasons.length === 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Missing seasons. If you want to cancel a tv request, use the DELETE method.'
|
'Missing seasons. If you want to cancel a series request, use the DELETE method.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -633,7 +645,7 @@ requestRoutes.delete('/:requestId', async (req, res, next) => {
|
|||||||
) {
|
) {
|
||||||
return next({
|
return next({
|
||||||
status: 401,
|
status: 401,
|
||||||
message: 'You do not have permission to remove this request',
|
message: 'You do not have permission to delete this request.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,7 +654,7 @@ requestRoutes.delete('/:requestId', async (req, res, next) => {
|
|||||||
return res.status(204).send();
|
return res.status(204).send();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(e.message);
|
logger.error(e.message);
|
||||||
next({ status: 404, message: 'Request not found' });
|
next({ status: 404, message: 'Request not found.' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -668,7 +680,7 @@ requestRoutes.post<{
|
|||||||
label: 'Media Request',
|
label: 'Media Request',
|
||||||
message: e.message,
|
message: e.message,
|
||||||
});
|
});
|
||||||
next({ status: 404, message: 'Request not found' });
|
next({ status: 404, message: 'Request not found.' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -712,7 +724,7 @@ requestRoutes.post<{
|
|||||||
label: 'Media Request',
|
label: 'Media Request',
|
||||||
message: e.message,
|
message: e.message,
|
||||||
});
|
});
|
||||||
next({ status: 404, message: 'Request not found' });
|
next({ status: 404, message: 'Request not found.' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@@ -13,7 +13,7 @@ const messages = defineMessages({
|
|||||||
validationemailrequired: 'You must provide a valid email address',
|
validationemailrequired: 'You must provide a valid email address',
|
||||||
validationpasswordrequired: 'You must provide a password',
|
validationpasswordrequired: 'You must provide a password',
|
||||||
loginerror: 'Something went wrong while trying to sign in.',
|
loginerror: 'Something went wrong while trying to sign in.',
|
||||||
signingin: 'Signing in…',
|
signingin: 'Signing In…',
|
||||||
signin: 'Sign In',
|
signin: 'Sign In',
|
||||||
forgotpassword: 'Forgot Password?',
|
forgotpassword: 'Forgot Password?',
|
||||||
});
|
});
|
||||||
|
@@ -6,7 +6,7 @@ import PlexOAuth from '../../utils/plex';
|
|||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
signinwithplex: 'Sign In',
|
signinwithplex: 'Sign In',
|
||||||
signingin: 'Signing in…',
|
signingin: 'Signing In…',
|
||||||
});
|
});
|
||||||
|
|
||||||
const plexOAuth = new PlexOAuth();
|
const plexOAuth = new PlexOAuth();
|
||||||
|
@@ -5,7 +5,7 @@ import {
|
|||||||
XIcon,
|
XIcon,
|
||||||
} from '@heroicons/react/solid';
|
} from '@heroicons/react/solid';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import React, { useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import {
|
import {
|
||||||
MediaRequestStatus,
|
MediaRequestStatus,
|
||||||
@@ -23,19 +23,19 @@ const messages = defineMessages({
|
|||||||
viewrequest: 'View Request',
|
viewrequest: 'View Request',
|
||||||
viewrequest4k: 'View 4K Request',
|
viewrequest4k: 'View 4K Request',
|
||||||
requestmore: 'Request More',
|
requestmore: 'Request More',
|
||||||
requestmore4k: 'Request More 4K',
|
requestmore4k: 'Request More in 4K',
|
||||||
approverequest: 'Approve Request',
|
approverequest: 'Approve Request',
|
||||||
approverequest4k: 'Approve 4K Request',
|
approverequest4k: 'Approve 4K Request',
|
||||||
declinerequest: 'Decline Request',
|
declinerequest: 'Decline Request',
|
||||||
declinerequest4k: 'Decline 4K Request',
|
declinerequest4k: 'Decline 4K Request',
|
||||||
approverequests:
|
approverequests:
|
||||||
'Approve {requestCount} {requestCount, plural, one {Request} other {Requests}}',
|
'Approve {requestCount, plural, one {Request} other {{requestCount} Requests}}',
|
||||||
declinerequests:
|
declinerequests:
|
||||||
'Decline {requestCount} {requestCount, plural, one {Request} other {Requests}}',
|
'Decline {requestCount, plural, one {Request} other {{requestCount} Requests}}',
|
||||||
approve4krequests:
|
approve4krequests:
|
||||||
'Approve {requestCount} 4K {requestCount, plural, one {Request} other {Requests}}',
|
'Approve {requestCount, plural, one {Request} other {{requestCount} 4K Requests}}',
|
||||||
decline4krequests:
|
decline4krequests:
|
||||||
'Decline {requestCount} 4K {requestCount, plural, one {Request} other {Requests}}',
|
'Decline {requestCount, plural, one {Request} other {{requestCount} 4K Requests}}',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface ButtonOption {
|
interface ButtonOption {
|
||||||
@@ -64,26 +64,34 @@ const RequestButton: React.FC<RequestButtonProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
const { hasPermission } = useUser();
|
const { user, hasPermission } = useUser();
|
||||||
const [showRequestModal, setShowRequestModal] = useState(false);
|
const [showRequestModal, setShowRequestModal] = useState(false);
|
||||||
const [showRequest4kModal, setShowRequest4kModal] = useState(false);
|
const [showRequest4kModal, setShowRequest4kModal] = useState(false);
|
||||||
|
const [editRequest, setEditRequest] = useState(false);
|
||||||
|
|
||||||
const activeRequest = media?.requests.find(
|
// All pending requests
|
||||||
(request) => request.status === MediaRequestStatus.PENDING && !request.is4k
|
|
||||||
);
|
|
||||||
const active4kRequest = media?.requests.find(
|
|
||||||
(request) => request.status === MediaRequestStatus.PENDING && request.is4k
|
|
||||||
);
|
|
||||||
|
|
||||||
// All pending
|
|
||||||
const activeRequests = media?.requests.filter(
|
const activeRequests = media?.requests.filter(
|
||||||
(request) => request.status === MediaRequestStatus.PENDING && !request.is4k
|
(request) => request.status === MediaRequestStatus.PENDING && !request.is4k
|
||||||
);
|
);
|
||||||
|
|
||||||
const active4kRequests = media?.requests.filter(
|
const active4kRequests = media?.requests.filter(
|
||||||
(request) => request.status === MediaRequestStatus.PENDING && request.is4k
|
(request) => request.status === MediaRequestStatus.PENDING && request.is4k
|
||||||
);
|
);
|
||||||
|
|
||||||
|
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(
|
||||||
|
(request) => request.requestedBy.id === user?.id
|
||||||
|
) ?? active4kRequests[0]
|
||||||
|
: undefined;
|
||||||
|
}, [active4kRequests, user]);
|
||||||
|
|
||||||
const modifyRequest = async (
|
const modifyRequest = async (
|
||||||
request: MediaRequest,
|
request: MediaRequest,
|
||||||
type: 'approve' | 'decline'
|
type: 'approve' | 'decline'
|
||||||
@@ -121,24 +129,7 @@ const RequestButton: React.FC<RequestButtonProps> = ({
|
|||||||
id: 'request',
|
id: 'request',
|
||||||
text: intl.formatMessage(globalMessages.request),
|
text: intl.formatMessage(globalMessages.request),
|
||||||
action: () => {
|
action: () => {
|
||||||
setShowRequestModal(true);
|
setEditRequest(false);
|
||||||
},
|
|
||||||
svg: <DownloadIcon className="w-5 h-5 mr-1" />,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
hasPermission(Permission.REQUEST) &&
|
|
||||||
mediaType === 'tv' &&
|
|
||||||
media &&
|
|
||||||
media.status !== MediaStatus.AVAILABLE &&
|
|
||||||
media.status !== MediaStatus.UNKNOWN &&
|
|
||||||
!isShowComplete
|
|
||||||
) {
|
|
||||||
buttons.push({
|
|
||||||
id: 'request-more',
|
|
||||||
text: intl.formatMessage(messages.requestmore),
|
|
||||||
action: () => {
|
|
||||||
setShowRequestModal(true);
|
setShowRequestModal(true);
|
||||||
},
|
},
|
||||||
svg: <DownloadIcon className="w-5 h-5 mr-1" />,
|
svg: <DownloadIcon className="w-5 h-5 mr-1" />,
|
||||||
@@ -157,26 +148,7 @@ const RequestButton: React.FC<RequestButtonProps> = ({
|
|||||||
id: 'request4k',
|
id: 'request4k',
|
||||||
text: intl.formatMessage(globalMessages.request4k),
|
text: intl.formatMessage(globalMessages.request4k),
|
||||||
action: () => {
|
action: () => {
|
||||||
setShowRequest4kModal(true);
|
setEditRequest(false);
|
||||||
},
|
|
||||||
svg: <DownloadIcon className="w-5 h-5 mr-1" />,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
mediaType === 'tv' &&
|
|
||||||
(hasPermission(Permission.REQUEST_4K) ||
|
|
||||||
(mediaType === 'tv' && hasPermission(Permission.REQUEST_4K_TV))) &&
|
|
||||||
media &&
|
|
||||||
media.status4k !== MediaStatus.AVAILABLE &&
|
|
||||||
media.status4k !== MediaStatus.UNKNOWN &&
|
|
||||||
!is4kShowComplete &&
|
|
||||||
settings.currentSettings.series4kEnabled
|
|
||||||
) {
|
|
||||||
buttons.push({
|
|
||||||
id: 'request-more-4k',
|
|
||||||
text: intl.formatMessage(messages.requestmore4k),
|
|
||||||
action: () => {
|
|
||||||
setShowRequest4kModal(true);
|
setShowRequest4kModal(true);
|
||||||
},
|
},
|
||||||
svg: <DownloadIcon className="w-5 h-5 mr-1" />,
|
svg: <DownloadIcon className="w-5 h-5 mr-1" />,
|
||||||
@@ -185,27 +157,34 @@ const RequestButton: React.FC<RequestButtonProps> = ({
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
activeRequest &&
|
activeRequest &&
|
||||||
mediaType === 'movie' &&
|
(activeRequest.requestedBy.id === user?.id ||
|
||||||
hasPermission(Permission.REQUEST)
|
(activeRequests?.length === 1 &&
|
||||||
|
hasPermission(Permission.MANAGE_REQUESTS)))
|
||||||
) {
|
) {
|
||||||
buttons.push({
|
buttons.push({
|
||||||
id: 'active-request',
|
id: 'active-request',
|
||||||
text: intl.formatMessage(messages.viewrequest),
|
text: intl.formatMessage(messages.viewrequest),
|
||||||
action: () => setShowRequestModal(true),
|
action: () => {
|
||||||
|
setEditRequest(true);
|
||||||
|
setShowRequestModal(true);
|
||||||
|
},
|
||||||
svg: <InformationCircleIcon className="w-5 h-5 mr-1" />,
|
svg: <InformationCircleIcon className="w-5 h-5 mr-1" />,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
active4kRequest &&
|
active4kRequest &&
|
||||||
mediaType === 'movie' &&
|
(active4kRequest.requestedBy.id === user?.id ||
|
||||||
(hasPermission(Permission.REQUEST_4K) ||
|
(active4kRequests?.length === 1 &&
|
||||||
hasPermission(Permission.REQUEST_4K_MOVIE))
|
hasPermission(Permission.MANAGE_REQUESTS)))
|
||||||
) {
|
) {
|
||||||
buttons.push({
|
buttons.push({
|
||||||
id: 'active-4k-request',
|
id: 'active-4k-request',
|
||||||
text: intl.formatMessage(messages.viewrequest4k),
|
text: intl.formatMessage(messages.viewrequest4k),
|
||||||
action: () => setShowRequest4kModal(true),
|
action: () => {
|
||||||
|
setEditRequest(true);
|
||||||
|
setShowRequest4kModal(true);
|
||||||
|
},
|
||||||
svg: <InformationCircleIcon className="w-5 h-5 mr-1" />,
|
svg: <InformationCircleIcon className="w-5 h-5 mr-1" />,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -320,6 +299,49 @@ const RequestButton: React.FC<RequestButtonProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
mediaType === 'tv' &&
|
||||||
|
(!activeRequest || activeRequest.requestedBy.id !== user?.id) &&
|
||||||
|
hasPermission(Permission.REQUEST) &&
|
||||||
|
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 className="w-5 h-5 mr-1" />,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
mediaType === 'tv' &&
|
||||||
|
(!active4kRequest || active4kRequest.requestedBy.id !== user?.id) &&
|
||||||
|
hasPermission([Permission.REQUEST_4K, Permission.REQUEST_4K_TV], {
|
||||||
|
type: 'or',
|
||||||
|
}) &&
|
||||||
|
media &&
|
||||||
|
media.status4k !== MediaStatus.AVAILABLE &&
|
||||||
|
media.status4k !== MediaStatus.UNKNOWN &&
|
||||||
|
!is4kShowComplete &&
|
||||||
|
settings.currentSettings.series4kEnabled
|
||||||
|
) {
|
||||||
|
buttons.push({
|
||||||
|
id: 'request-more-4k',
|
||||||
|
text: intl.formatMessage(messages.requestmore4k),
|
||||||
|
action: () => {
|
||||||
|
setEditRequest(false);
|
||||||
|
setShowRequest4kModal(true);
|
||||||
|
},
|
||||||
|
svg: <DownloadIcon className="w-5 h-5 mr-1" />,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const [buttonOne, ...others] = buttons;
|
const [buttonOne, ...others] = buttons;
|
||||||
|
|
||||||
if (!buttonOne) {
|
if (!buttonOne) {
|
||||||
@@ -332,6 +354,7 @@ const RequestButton: React.FC<RequestButtonProps> = ({
|
|||||||
tmdbId={tmdbId}
|
tmdbId={tmdbId}
|
||||||
show={showRequestModal}
|
show={showRequestModal}
|
||||||
type={mediaType}
|
type={mediaType}
|
||||||
|
editRequest={editRequest ? activeRequest : undefined}
|
||||||
onComplete={() => {
|
onComplete={() => {
|
||||||
onUpdate();
|
onUpdate();
|
||||||
setShowRequestModal(false);
|
setShowRequestModal(false);
|
||||||
@@ -342,6 +365,7 @@ const RequestButton: React.FC<RequestButtonProps> = ({
|
|||||||
tmdbId={tmdbId}
|
tmdbId={tmdbId}
|
||||||
show={showRequest4kModal}
|
show={showRequest4kModal}
|
||||||
type={mediaType}
|
type={mediaType}
|
||||||
|
editRequest={editRequest ? active4kRequest : undefined}
|
||||||
is4k
|
is4k
|
||||||
onComplete={() => {
|
onComplete={() => {
|
||||||
onUpdate();
|
onUpdate();
|
||||||
|
@@ -36,6 +36,7 @@ const messages = defineMessages({
|
|||||||
modified: 'Modified',
|
modified: 'Modified',
|
||||||
modifieduserdate: '{date} by {user}',
|
modifieduserdate: '{date} by {user}',
|
||||||
mediaerror: 'The associated title for this request is no longer available.',
|
mediaerror: 'The associated title for this request is no longer available.',
|
||||||
|
editrequest: 'Edit Request',
|
||||||
deleterequest: 'Delete Request',
|
deleterequest: 'Delete Request',
|
||||||
cancelRequest: 'Cancel Request',
|
cancelRequest: 'Cancel Request',
|
||||||
});
|
});
|
||||||
@@ -363,20 +364,6 @@ const RequestItem: React.FC<RequestItemProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="z-10 flex flex-col justify-center w-full pl-4 pr-4 mt-4 space-y-2 xl:mt-0 xl:items-end xl:w-96 xl:pl-0">
|
<div className="z-10 flex flex-col justify-center w-full pl-4 pr-4 mt-4 space-y-2 xl:mt-0 xl:items-end xl:w-96 xl:pl-0">
|
||||||
{requestData.status === MediaRequestStatus.PENDING &&
|
|
||||||
!hasPermission(Permission.MANAGE_REQUESTS) &&
|
|
||||||
requestData.requestedBy.id === user?.id && (
|
|
||||||
<ConfirmButton
|
|
||||||
onClick={() => deleteRequest()}
|
|
||||||
confirmText={intl.formatMessage(globalMessages.areyousure)}
|
|
||||||
className="w-full"
|
|
||||||
>
|
|
||||||
<XIcon className="w-5 h-5 mr-1" />
|
|
||||||
<span className="block">
|
|
||||||
{intl.formatMessage(messages.cancelRequest)}
|
|
||||||
</span>
|
|
||||||
</ConfirmButton>
|
|
||||||
)}
|
|
||||||
{requestData.media[requestData.is4k ? 'status4k' : 'status'] ===
|
{requestData.media[requestData.is4k ? 'status4k' : 'status'] ===
|
||||||
MediaStatus.UNKNOWN &&
|
MediaStatus.UNKNOWN &&
|
||||||
requestData.status !== MediaRequestStatus.DECLINED &&
|
requestData.status !== MediaRequestStatus.DECLINED &&
|
||||||
@@ -407,13 +394,12 @@ const RequestItem: React.FC<RequestItemProps> = ({
|
|||||||
>
|
>
|
||||||
<TrashIcon className="w-5 h-5 mr-1" />
|
<TrashIcon className="w-5 h-5 mr-1" />
|
||||||
<span className="block">
|
<span className="block">
|
||||||
{intl.formatMessage(globalMessages.delete)}
|
{intl.formatMessage(messages.deleterequest)}
|
||||||
</span>
|
</span>
|
||||||
</ConfirmButton>
|
</ConfirmButton>
|
||||||
)}
|
)}
|
||||||
{requestData.status === MediaRequestStatus.PENDING &&
|
{requestData.status === MediaRequestStatus.PENDING &&
|
||||||
hasPermission(Permission.MANAGE_REQUESTS) && (
|
hasPermission(Permission.MANAGE_REQUESTS) && (
|
||||||
<>
|
|
||||||
<div className="flex flex-row w-full space-x-2">
|
<div className="flex flex-row w-full space-x-2">
|
||||||
<span className="w-full">
|
<span className="w-full">
|
||||||
<Button
|
<Button
|
||||||
@@ -440,6 +426,12 @@ const RequestItem: React.FC<RequestItemProps> = ({
|
|||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{requestData.status === MediaRequestStatus.PENDING &&
|
||||||
|
(hasPermission(Permission.MANAGE_REQUESTS) ||
|
||||||
|
(requestData.requestedBy.id === user?.id &&
|
||||||
|
(requestData.type === 'tv' ||
|
||||||
|
hasPermission(Permission.REQUEST_ADVANCED)))) && (
|
||||||
<span className="w-full">
|
<span className="w-full">
|
||||||
<Button
|
<Button
|
||||||
className="w-full"
|
className="w-full"
|
||||||
@@ -448,11 +440,24 @@ const RequestItem: React.FC<RequestItemProps> = ({
|
|||||||
>
|
>
|
||||||
<PencilIcon className="w-5 h-5 mr-1" />
|
<PencilIcon className="w-5 h-5 mr-1" />
|
||||||
<span className="block">
|
<span className="block">
|
||||||
{intl.formatMessage(globalMessages.edit)}
|
{intl.formatMessage(messages.editrequest)}
|
||||||
</span>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</span>
|
</span>
|
||||||
</>
|
)}
|
||||||
|
{requestData.status === MediaRequestStatus.PENDING &&
|
||||||
|
!hasPermission(Permission.MANAGE_REQUESTS) &&
|
||||||
|
requestData.requestedBy.id === user?.id && (
|
||||||
|
<ConfirmButton
|
||||||
|
onClick={() => deleteRequest()}
|
||||||
|
confirmText={intl.formatMessage(globalMessages.areyousure)}
|
||||||
|
className="w-full"
|
||||||
|
>
|
||||||
|
<XIcon className="w-5 h-5 mr-1" />
|
||||||
|
<span className="block">
|
||||||
|
{intl.formatMessage(messages.cancelRequest)}
|
||||||
|
</span>
|
||||||
|
</ConfirmButton>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -4,10 +4,7 @@ import React, { useCallback, useEffect, useState } from 'react';
|
|||||||
import { defineMessages, useIntl } from 'react-intl';
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
import { useToasts } from 'react-toast-notifications';
|
import { useToasts } from 'react-toast-notifications';
|
||||||
import useSWR from 'swr';
|
import useSWR from 'swr';
|
||||||
import {
|
import { MediaStatus } from '../../../server/constants/media';
|
||||||
MediaRequestStatus,
|
|
||||||
MediaStatus,
|
|
||||||
} from '../../../server/constants/media';
|
|
||||||
import { MediaRequest } from '../../../server/entity/MediaRequest';
|
import { MediaRequest } from '../../../server/entity/MediaRequest';
|
||||||
import { QuotaResponse } from '../../../server/interfaces/api/userInterfaces';
|
import { QuotaResponse } from '../../../server/interfaces/api/userInterfaces';
|
||||||
import { Permission } from '../../../server/lib/permissions';
|
import { Permission } from '../../../server/lib/permissions';
|
||||||
@@ -25,11 +22,11 @@ const messages = defineMessages({
|
|||||||
requestCancel: 'Request for <strong>{title}</strong> canceled.',
|
requestCancel: 'Request for <strong>{title}</strong> canceled.',
|
||||||
requesttitle: 'Request {title}',
|
requesttitle: 'Request {title}',
|
||||||
request4ktitle: 'Request {title} in 4K',
|
request4ktitle: 'Request {title} in 4K',
|
||||||
|
edit: 'Edit Request',
|
||||||
cancel: 'Cancel Request',
|
cancel: 'Cancel Request',
|
||||||
pendingrequest: 'Pending Request for {title}',
|
pendingrequest: 'Pending Request for {title}',
|
||||||
pending4krequest: 'Pending Request for {title} in 4K',
|
pending4krequest: 'Pending 4K Request for {title}',
|
||||||
requestfrom: 'There is currently a pending request from {username}.',
|
requestfrom: "{username}'s request is pending approval.",
|
||||||
request4kfrom: 'There is currently a pending 4K request from {username}.',
|
|
||||||
errorediting: 'Something went wrong while editing the request.',
|
errorediting: 'Something went wrong while editing the request.',
|
||||||
requestedited: 'Request for <strong>{title}</strong> edited successfully!',
|
requestedited: 'Request for <strong>{title}</strong> edited successfully!',
|
||||||
requesterror: 'Something went wrong while submitting the request.',
|
requesterror: 'Something went wrong while submitting the request.',
|
||||||
@@ -130,18 +127,14 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
|
|||||||
} finally {
|
} finally {
|
||||||
setIsUpdating(false);
|
setIsUpdating(false);
|
||||||
}
|
}
|
||||||
}, [data, onComplete, addToast, requestOverrides]);
|
}, [data, onComplete, addToast, requestOverrides, hasPermission, intl, is4k]);
|
||||||
|
|
||||||
const activeRequest = data?.mediaInfo?.requests?.find(
|
|
||||||
(request) => request.is4k === !!is4k
|
|
||||||
);
|
|
||||||
|
|
||||||
const cancelRequest = async () => {
|
const cancelRequest = async () => {
|
||||||
setIsUpdating(true);
|
setIsUpdating(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await axios.delete<MediaRequest>(
|
const response = await axios.delete<MediaRequest>(
|
||||||
`/api/v1/request/${activeRequest?.id}`
|
`/api/v1/request/${editRequest?.id}`
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.status === 204) {
|
if (response.status === 204) {
|
||||||
@@ -206,11 +199,15 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isOwner = activeRequest
|
if (editRequest) {
|
||||||
? activeRequest.requestedBy.id === user?.id
|
const isOwner = editRequest.requestedBy.id === user?.id;
|
||||||
: false;
|
const showEditButton = hasPermission(
|
||||||
|
[Permission.MANAGE_REQUESTS, Permission.REQUEST_ADVANCED],
|
||||||
|
{
|
||||||
|
type: 'or',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
if (activeRequest?.status === MediaRequestStatus.PENDING) {
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
loading={!data && !error}
|
loading={!data && !error}
|
||||||
@@ -218,48 +215,47 @@ const MovieRequestModal: React.FC<RequestModalProps> = ({
|
|||||||
onCancel={onCancel}
|
onCancel={onCancel}
|
||||||
title={intl.formatMessage(
|
title={intl.formatMessage(
|
||||||
is4k ? messages.pending4krequest : messages.pendingrequest,
|
is4k ? messages.pending4krequest : messages.pendingrequest,
|
||||||
{
|
{ title: data?.title }
|
||||||
title: data?.title,
|
|
||||||
}
|
|
||||||
)}
|
)}
|
||||||
onOk={() => (isOwner ? cancelRequest() : updateRequest())}
|
onOk={() => (showEditButton ? updateRequest() : cancelRequest())}
|
||||||
okDisabled={isUpdating}
|
okDisabled={isUpdating}
|
||||||
okText={
|
okText={
|
||||||
isOwner
|
showEditButton
|
||||||
? isUpdating
|
? intl.formatMessage(messages.edit)
|
||||||
? intl.formatMessage(globalMessages.canceling)
|
|
||||||
: intl.formatMessage(messages.cancel)
|
: intl.formatMessage(messages.cancel)
|
||||||
: intl.formatMessage(globalMessages.edit)
|
|
||||||
}
|
}
|
||||||
okButtonType={isOwner ? 'danger' : 'primary'}
|
okButtonType={showEditButton ? 'primary' : 'danger'}
|
||||||
|
onSecondary={
|
||||||
|
isOwner && showEditButton ? () => cancelRequest() : undefined
|
||||||
|
}
|
||||||
|
secondaryDisabled={isUpdating}
|
||||||
|
secondaryText={
|
||||||
|
isOwner && showEditButton
|
||||||
|
? intl.formatMessage(messages.cancel)
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
|
secondaryButtonType="danger"
|
||||||
cancelText={intl.formatMessage(globalMessages.close)}
|
cancelText={intl.formatMessage(globalMessages.close)}
|
||||||
iconSvg={<DownloadIcon className="w-6 h-6" />}
|
iconSvg={<DownloadIcon className="w-6 h-6" />}
|
||||||
>
|
>
|
||||||
{isOwner
|
{isOwner
|
||||||
? intl.formatMessage(messages.pendingapproval)
|
? intl.formatMessage(messages.pendingapproval)
|
||||||
: intl.formatMessage(
|
: intl.formatMessage(messages.requestfrom, {
|
||||||
is4k ? messages.request4kfrom : messages.requestfrom,
|
username: editRequest.requestedBy.displayName,
|
||||||
{
|
})}
|
||||||
username: activeRequest.requestedBy.displayName,
|
|
||||||
}
|
|
||||||
)}
|
|
||||||
{(hasPermission(Permission.REQUEST_ADVANCED) ||
|
{(hasPermission(Permission.REQUEST_ADVANCED) ||
|
||||||
hasPermission(Permission.MANAGE_REQUESTS)) && (
|
hasPermission(Permission.MANAGE_REQUESTS)) && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<AdvancedRequester
|
<AdvancedRequester
|
||||||
type="movie"
|
type="movie"
|
||||||
is4k={is4k}
|
is4k={is4k}
|
||||||
requestUser={editRequest?.requestedBy}
|
requestUser={editRequest.requestedBy}
|
||||||
defaultOverrides={
|
defaultOverrides={{
|
||||||
editRequest
|
|
||||||
? {
|
|
||||||
folder: editRequest.rootFolder,
|
folder: editRequest.rootFolder,
|
||||||
profile: editRequest.profileId,
|
profile: editRequest.profileId,
|
||||||
server: editRequest.serverId,
|
server: editRequest.serverId,
|
||||||
tags: editRequest.tags,
|
tags: editRequest.tags,
|
||||||
}
|
}}
|
||||||
: undefined
|
|
||||||
}
|
|
||||||
onChange={(overrides) => {
|
onChange={(overrides) => {
|
||||||
setRequestOverrides(overrides);
|
setRequestOverrides(overrides);
|
||||||
}}
|
}}
|
||||||
|
@@ -29,6 +29,11 @@ const messages = defineMessages({
|
|||||||
requestSuccess: '<strong>{title}</strong> requested successfully!',
|
requestSuccess: '<strong>{title}</strong> requested successfully!',
|
||||||
requesttitle: 'Request {title}',
|
requesttitle: 'Request {title}',
|
||||||
request4ktitle: 'Request {title} in 4K',
|
request4ktitle: 'Request {title} in 4K',
|
||||||
|
edit: 'Edit Request',
|
||||||
|
cancel: 'Cancel Request',
|
||||||
|
pendingrequest: 'Pending Request for {title}',
|
||||||
|
pending4krequest: 'Pending 4K Request for {title}',
|
||||||
|
requestfrom: "{username}'s request is pending approval.",
|
||||||
requestseasons:
|
requestseasons:
|
||||||
'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}',
|
'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}',
|
||||||
requestall: 'Request All Seasons',
|
requestall: 'Request All Seasons',
|
||||||
@@ -43,6 +48,7 @@ const messages = defineMessages({
|
|||||||
requestcancelled: 'Request for <strong>{title}</strong> canceled.',
|
requestcancelled: 'Request for <strong>{title}</strong> canceled.',
|
||||||
autoapproval: 'Automatic Approval',
|
autoapproval: 'Automatic Approval',
|
||||||
requesterror: 'Something went wrong while submitting the request.',
|
requesterror: 'Something went wrong while submitting the request.',
|
||||||
|
pendingapproval: 'Your request is pending approval.',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {
|
interface RequestModalProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||||
@@ -342,6 +348,8 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
|
|||||||
return seasonRequest;
|
return seasonRequest;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isOwner = editRequest && editRequest.requestedBy.id === user?.id;
|
||||||
|
|
||||||
return !data?.externalIds.tvdbId && searchModal.show ? (
|
return !data?.externalIds.tvdbId && searchModal.show ? (
|
||||||
<SearchByNameModal
|
<SearchByNameModal
|
||||||
tvdbId={tvdbId}
|
tvdbId={tvdbId}
|
||||||
@@ -362,12 +370,20 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
|
|||||||
onCancel={tvdbId ? () => setSearchModal({ show: true }) : onCancel}
|
onCancel={tvdbId ? () => setSearchModal({ show: true }) : onCancel}
|
||||||
onOk={() => (editRequest ? updateRequest() : sendRequest())}
|
onOk={() => (editRequest ? updateRequest() : sendRequest())}
|
||||||
title={intl.formatMessage(
|
title={intl.formatMessage(
|
||||||
is4k ? messages.request4ktitle : messages.requesttitle,
|
editRequest
|
||||||
|
? is4k
|
||||||
|
? messages.pending4krequest
|
||||||
|
: messages.pendingrequest
|
||||||
|
: is4k
|
||||||
|
? messages.request4ktitle
|
||||||
|
: messages.requesttitle,
|
||||||
{ title: data?.name }
|
{ title: data?.name }
|
||||||
)}
|
)}
|
||||||
okText={
|
okText={
|
||||||
editRequest && selectedSeasons.length === 0
|
editRequest
|
||||||
? 'Cancel Request'
|
? selectedSeasons.length === 0
|
||||||
|
? intl.formatMessage(messages.cancel)
|
||||||
|
: intl.formatMessage(messages.edit)
|
||||||
: getAllRequestedSeasons().length >= getAllSeasons().length
|
: getAllRequestedSeasons().length >= getAllSeasons().length
|
||||||
? intl.formatMessage(messages.alreadyrequested)
|
? intl.formatMessage(messages.alreadyrequested)
|
||||||
: !settings.currentSettings.partialRequestsEnabled
|
: !settings.currentSettings.partialRequestsEnabled
|
||||||
@@ -397,12 +413,21 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
|
|||||||
: `primary`
|
: `primary`
|
||||||
}
|
}
|
||||||
cancelText={
|
cancelText={
|
||||||
tvdbId
|
editRequest
|
||||||
|
? intl.formatMessage(globalMessages.close)
|
||||||
|
: tvdbId
|
||||||
? intl.formatMessage(globalMessages.back)
|
? intl.formatMessage(globalMessages.back)
|
||||||
: intl.formatMessage(globalMessages.cancel)
|
: intl.formatMessage(globalMessages.cancel)
|
||||||
}
|
}
|
||||||
iconSvg={<DownloadIcon className="w-6 h-6" />}
|
iconSvg={<DownloadIcon className="w-6 h-6" />}
|
||||||
>
|
>
|
||||||
|
{editRequest
|
||||||
|
? isOwner
|
||||||
|
? intl.formatMessage(messages.pendingapproval)
|
||||||
|
: intl.formatMessage(messages.requestfrom, {
|
||||||
|
username: editRequest?.requestedBy.displayName,
|
||||||
|
})
|
||||||
|
: null}
|
||||||
{hasPermission(
|
{hasPermission(
|
||||||
[
|
[
|
||||||
Permission.MANAGE_REQUESTS,
|
Permission.MANAGE_REQUESTS,
|
||||||
|
@@ -63,7 +63,7 @@ const messages = defineMessages({
|
|||||||
'Password is too short; should be a minimum of 8 characters',
|
'Password is too short; should be a minimum of 8 characters',
|
||||||
usercreatedfailed: 'Something went wrong while creating the user.',
|
usercreatedfailed: 'Something went wrong while creating the user.',
|
||||||
usercreatedfailedexisting:
|
usercreatedfailedexisting:
|
||||||
'Provided email is already in use by another user.',
|
'The provided email address is already in use by another user.',
|
||||||
usercreatedsuccess: 'User created successfully!',
|
usercreatedsuccess: 'User created successfully!',
|
||||||
email: 'Email Address',
|
email: 'Email Address',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
|
@@ -9,7 +9,7 @@ const globalMessages = defineMessages({
|
|||||||
requested: 'Requested',
|
requested: 'Requested',
|
||||||
requesting: 'Requesting…',
|
requesting: 'Requesting…',
|
||||||
request: 'Request',
|
request: 'Request',
|
||||||
request4k: 'Request 4K',
|
request4k: 'Request in 4K',
|
||||||
failed: 'Failed',
|
failed: 'Failed',
|
||||||
pending: 'Pending',
|
pending: 'Pending',
|
||||||
declined: 'Declined',
|
declined: 'Declined',
|
||||||
|
@@ -52,7 +52,7 @@
|
|||||||
"components.Login.loginerror": "Something went wrong while trying to sign in.",
|
"components.Login.loginerror": "Something went wrong while trying to sign in.",
|
||||||
"components.Login.password": "Password",
|
"components.Login.password": "Password",
|
||||||
"components.Login.signin": "Sign In",
|
"components.Login.signin": "Sign In",
|
||||||
"components.Login.signingin": "Signing in…",
|
"components.Login.signingin": "Signing In…",
|
||||||
"components.Login.signinheader": "Sign in to continue",
|
"components.Login.signinheader": "Sign in to continue",
|
||||||
"components.Login.signinwithoverseerr": "Use your {applicationTitle} account",
|
"components.Login.signinwithoverseerr": "Use your {applicationTitle} account",
|
||||||
"components.Login.signinwithplex": "Use your Plex account",
|
"components.Login.signinwithplex": "Use your Plex account",
|
||||||
@@ -140,7 +140,7 @@
|
|||||||
"components.PersonDetails.birthdate": "Born {birthdate}",
|
"components.PersonDetails.birthdate": "Born {birthdate}",
|
||||||
"components.PersonDetails.crewmember": "Crew",
|
"components.PersonDetails.crewmember": "Crew",
|
||||||
"components.PersonDetails.lifespan": "{birthdate} – {deathdate}",
|
"components.PersonDetails.lifespan": "{birthdate} – {deathdate}",
|
||||||
"components.PlexLoginButton.signingin": "Signing in…",
|
"components.PlexLoginButton.signingin": "Signing In…",
|
||||||
"components.PlexLoginButton.signinwithplex": "Sign In",
|
"components.PlexLoginButton.signinwithplex": "Sign In",
|
||||||
"components.QuotaSelector.movieRequestLimit": "{quotaLimit} movie(s) per {quotaDays} day(s)",
|
"components.QuotaSelector.movieRequestLimit": "{quotaLimit} movie(s) per {quotaDays} day(s)",
|
||||||
"components.QuotaSelector.tvRequestLimit": "{quotaLimit} season(s) per {quotaDays} day(s)",
|
"components.QuotaSelector.tvRequestLimit": "{quotaLimit} season(s) per {quotaDays} day(s)",
|
||||||
@@ -152,16 +152,16 @@
|
|||||||
"components.RequestBlock.rootfolder": "Root Folder",
|
"components.RequestBlock.rootfolder": "Root Folder",
|
||||||
"components.RequestBlock.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
|
"components.RequestBlock.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
|
||||||
"components.RequestBlock.server": "Destination Server",
|
"components.RequestBlock.server": "Destination Server",
|
||||||
"components.RequestButton.approve4krequests": "Approve {requestCount} 4K {requestCount, plural, one {Request} other {Requests}}",
|
"components.RequestButton.approve4krequests": "Approve {requestCount, plural, one {Request} other {{requestCount} 4K Requests}}",
|
||||||
"components.RequestButton.approverequest": "Approve Request",
|
"components.RequestButton.approverequest": "Approve Request",
|
||||||
"components.RequestButton.approverequest4k": "Approve 4K Request",
|
"components.RequestButton.approverequest4k": "Approve 4K Request",
|
||||||
"components.RequestButton.approverequests": "Approve {requestCount} {requestCount, plural, one {Request} other {Requests}}",
|
"components.RequestButton.approverequests": "Approve {requestCount, plural, one {Request} other {{requestCount} Requests}}",
|
||||||
"components.RequestButton.decline4krequests": "Decline {requestCount} 4K {requestCount, plural, one {Request} other {Requests}}",
|
"components.RequestButton.decline4krequests": "Decline {requestCount, plural, one {Request} other {{requestCount} 4K Requests}}",
|
||||||
"components.RequestButton.declinerequest": "Decline Request",
|
"components.RequestButton.declinerequest": "Decline Request",
|
||||||
"components.RequestButton.declinerequest4k": "Decline 4K Request",
|
"components.RequestButton.declinerequest4k": "Decline 4K Request",
|
||||||
"components.RequestButton.declinerequests": "Decline {requestCount} {requestCount, plural, one {Request} other {Requests}}",
|
"components.RequestButton.declinerequests": "Decline {requestCount, plural, one {Request} other {{requestCount} Requests}}",
|
||||||
"components.RequestButton.requestmore": "Request More",
|
"components.RequestButton.requestmore": "Request More",
|
||||||
"components.RequestButton.requestmore4k": "Request More 4K",
|
"components.RequestButton.requestmore4k": "Request More in 4K",
|
||||||
"components.RequestButton.viewrequest": "View Request",
|
"components.RequestButton.viewrequest": "View Request",
|
||||||
"components.RequestButton.viewrequest4k": "View 4K Request",
|
"components.RequestButton.viewrequest4k": "View 4K Request",
|
||||||
"components.RequestCard.deleterequest": "Delete Request",
|
"components.RequestCard.deleterequest": "Delete Request",
|
||||||
@@ -169,6 +169,7 @@
|
|||||||
"components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
|
"components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
|
||||||
"components.RequestList.RequestItem.cancelRequest": "Cancel Request",
|
"components.RequestList.RequestItem.cancelRequest": "Cancel Request",
|
||||||
"components.RequestList.RequestItem.deleterequest": "Delete Request",
|
"components.RequestList.RequestItem.deleterequest": "Delete Request",
|
||||||
|
"components.RequestList.RequestItem.editrequest": "Edit Request",
|
||||||
"components.RequestList.RequestItem.failedretry": "Something went wrong while retrying the request.",
|
"components.RequestList.RequestItem.failedretry": "Something went wrong while retrying the request.",
|
||||||
"components.RequestList.RequestItem.mediaerror": "The associated title for this request is no longer available.",
|
"components.RequestList.RequestItem.mediaerror": "The associated title for this request is no longer available.",
|
||||||
"components.RequestList.RequestItem.modified": "Modified",
|
"components.RequestList.RequestItem.modified": "Modified",
|
||||||
@@ -208,13 +209,13 @@
|
|||||||
"components.RequestModal.alreadyrequested": "Already Requested",
|
"components.RequestModal.alreadyrequested": "Already Requested",
|
||||||
"components.RequestModal.autoapproval": "Automatic Approval",
|
"components.RequestModal.autoapproval": "Automatic Approval",
|
||||||
"components.RequestModal.cancel": "Cancel Request",
|
"components.RequestModal.cancel": "Cancel Request",
|
||||||
|
"components.RequestModal.edit": "Edit Request",
|
||||||
"components.RequestModal.errorediting": "Something went wrong while editing the request.",
|
"components.RequestModal.errorediting": "Something went wrong while editing the request.",
|
||||||
"components.RequestModal.extras": "Extras",
|
"components.RequestModal.extras": "Extras",
|
||||||
"components.RequestModal.numberofepisodes": "# of Episodes",
|
"components.RequestModal.numberofepisodes": "# of Episodes",
|
||||||
"components.RequestModal.pending4krequest": "Pending Request for {title} in 4K",
|
"components.RequestModal.pending4krequest": "Pending 4K Request for {title}",
|
||||||
"components.RequestModal.pendingapproval": "Your request is pending approval.",
|
"components.RequestModal.pendingapproval": "Your request is pending approval.",
|
||||||
"components.RequestModal.pendingrequest": "Pending Request for {title}",
|
"components.RequestModal.pendingrequest": "Pending Request for {title}",
|
||||||
"components.RequestModal.request4kfrom": "There is currently a pending 4K request from {username}.",
|
|
||||||
"components.RequestModal.request4ktitle": "Request {title} in 4K",
|
"components.RequestModal.request4ktitle": "Request {title} in 4K",
|
||||||
"components.RequestModal.requestCancel": "Request for <strong>{title}</strong> canceled.",
|
"components.RequestModal.requestCancel": "Request for <strong>{title}</strong> canceled.",
|
||||||
"components.RequestModal.requestSuccess": "<strong>{title}</strong> requested successfully!",
|
"components.RequestModal.requestSuccess": "<strong>{title}</strong> requested successfully!",
|
||||||
@@ -223,7 +224,7 @@
|
|||||||
"components.RequestModal.requestcancelled": "Request for <strong>{title}</strong> canceled.",
|
"components.RequestModal.requestcancelled": "Request for <strong>{title}</strong> canceled.",
|
||||||
"components.RequestModal.requestedited": "Request for <strong>{title}</strong> edited successfully!",
|
"components.RequestModal.requestedited": "Request for <strong>{title}</strong> edited successfully!",
|
||||||
"components.RequestModal.requesterror": "Something went wrong while submitting the request.",
|
"components.RequestModal.requesterror": "Something went wrong while submitting the request.",
|
||||||
"components.RequestModal.requestfrom": "There is currently a pending request from {username}.",
|
"components.RequestModal.requestfrom": "{username}'s request is pending approval.",
|
||||||
"components.RequestModal.requestseasons": "Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}",
|
"components.RequestModal.requestseasons": "Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}",
|
||||||
"components.RequestModal.requesttitle": "Request {title}",
|
"components.RequestModal.requesttitle": "Request {title}",
|
||||||
"components.RequestModal.season": "Season",
|
"components.RequestModal.season": "Season",
|
||||||
@@ -677,6 +678,7 @@
|
|||||||
"components.UserList.totalrequests": "Total Requests",
|
"components.UserList.totalrequests": "Total Requests",
|
||||||
"components.UserList.user": "User",
|
"components.UserList.user": "User",
|
||||||
"components.UserList.usercreatedfailed": "Something went wrong while creating the user.",
|
"components.UserList.usercreatedfailed": "Something went wrong while creating the user.",
|
||||||
|
"components.UserList.usercreatedfailedexisting": "The provided email address is already in use by another user.",
|
||||||
"components.UserList.usercreatedsuccess": "User created successfully!",
|
"components.UserList.usercreatedsuccess": "User created successfully!",
|
||||||
"components.UserList.userdeleted": "User deleted successfully!",
|
"components.UserList.userdeleted": "User deleted successfully!",
|
||||||
"components.UserList.userdeleteerror": "Something went wrong while deleting the user.",
|
"components.UserList.userdeleteerror": "Something went wrong while deleting the user.",
|
||||||
@@ -796,7 +798,7 @@
|
|||||||
"i18n.previous": "Previous",
|
"i18n.previous": "Previous",
|
||||||
"i18n.processing": "Processing",
|
"i18n.processing": "Processing",
|
||||||
"i18n.request": "Request",
|
"i18n.request": "Request",
|
||||||
"i18n.request4k": "Request 4K",
|
"i18n.request4k": "Request in 4K",
|
||||||
"i18n.requested": "Requested",
|
"i18n.requested": "Requested",
|
||||||
"i18n.requesting": "Requesting…",
|
"i18n.requesting": "Requesting…",
|
||||||
"i18n.resultsperpage": "Display {pageSize} results per page",
|
"i18n.resultsperpage": "Display {pageSize} results per page",
|
||||||
|
Reference in New Issue
Block a user