feat(frontend): a few more tooltips (#2972)
* feat(frontend): a few more tooltips * feat: add tooltips to status badges
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
interface BadgeProps {
|
interface BadgeProps {
|
||||||
badgeType?:
|
badgeType?:
|
||||||
@@ -14,12 +15,10 @@ interface BadgeProps {
|
|||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Badge = ({
|
const Badge = (
|
||||||
badgeType = 'default',
|
{ badgeType = 'default', className, href, children }: BadgeProps,
|
||||||
className,
|
ref?: React.Ref<HTMLElement>
|
||||||
href,
|
) => {
|
||||||
children,
|
|
||||||
}: BadgeProps) => {
|
|
||||||
const badgeStyle = [
|
const badgeStyle = [
|
||||||
'px-2 inline-flex text-xs leading-5 font-semibold rounded-full whitespace-nowrap',
|
'px-2 inline-flex text-xs leading-5 font-semibold rounded-full whitespace-nowrap',
|
||||||
];
|
];
|
||||||
@@ -79,6 +78,7 @@ const Badge = ({
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className={badgeStyle.join(' ')}
|
className={badgeStyle.join(' ')}
|
||||||
|
ref={ref as React.Ref<HTMLAnchorElement>}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</a>
|
</a>
|
||||||
@@ -86,12 +86,24 @@ const Badge = ({
|
|||||||
} else if (href) {
|
} else if (href) {
|
||||||
return (
|
return (
|
||||||
<Link href={href}>
|
<Link href={href}>
|
||||||
<a className={badgeStyle.join(' ')}>{children}</a>
|
<a
|
||||||
|
className={badgeStyle.join(' ')}
|
||||||
|
ref={ref as React.Ref<HTMLAnchorElement>}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return <span className={badgeStyle.join(' ')}>{children}</span>;
|
return (
|
||||||
|
<span
|
||||||
|
className={badgeStyle.join(' ')}
|
||||||
|
ref={ref as React.Ref<HTMLSpanElement>}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Badge;
|
export default React.forwardRef(Badge) as typeof Badge;
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const ExternalLinkBlock = ({
|
|||||||
)}
|
)}
|
||||||
{rtUrl && (
|
{rtUrl && (
|
||||||
<a
|
<a
|
||||||
href={`${rtUrl}`}
|
href={rtUrl}
|
||||||
className="w-14 opacity-50 transition duration-300 hover:opacity-100"
|
className="w-14 opacity-50 transition duration-300 hover:opacity-100"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ const messages = defineMessages({
|
|||||||
physicalrelease: 'Physical Release',
|
physicalrelease: 'Physical Release',
|
||||||
reportissue: 'Report an Issue',
|
reportissue: 'Report an Issue',
|
||||||
managemovie: 'Manage Movie',
|
managemovie: 'Manage Movie',
|
||||||
|
rtcriticsscore: 'Rotten Tomatoes Tomatometer',
|
||||||
|
rtaudiencescore: 'Rotten Tomatoes Audience Score',
|
||||||
|
tmdbuserscore: 'TMDB User Score',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface MovieDetailsProps {
|
interface MovieDetailsProps {
|
||||||
@@ -322,6 +325,7 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
|||||||
tmdbId={data.mediaInfo?.tmdbId}
|
tmdbId={data.mediaInfo?.tmdbId}
|
||||||
mediaType="movie"
|
mediaType="movie"
|
||||||
plexUrl={data.mediaInfo?.plexUrl}
|
plexUrl={data.mediaInfo?.plexUrl}
|
||||||
|
serviceUrl={data.mediaInfo?.serviceUrl}
|
||||||
/>
|
/>
|
||||||
{settings.currentSettings.movie4kEnabled &&
|
{settings.currentSettings.movie4kEnabled &&
|
||||||
hasPermission(
|
hasPermission(
|
||||||
@@ -343,6 +347,7 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
|||||||
tmdbId={data.mediaInfo?.tmdbId}
|
tmdbId={data.mediaInfo?.tmdbId}
|
||||||
mediaType="movie"
|
mediaType="movie"
|
||||||
plexUrl={data.mediaInfo?.plexUrl4k}
|
plexUrl={data.mediaInfo?.plexUrl4k}
|
||||||
|
serviceUrl={data.mediaInfo?.serviceUrl4k}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -499,36 +504,55 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
|||||||
(ratingData?.audienceRating && !!ratingData?.audienceScore)) && (
|
(ratingData?.audienceRating && !!ratingData?.audienceScore)) && (
|
||||||
<div className="media-ratings">
|
<div className="media-ratings">
|
||||||
{ratingData?.criticsRating && !!ratingData?.criticsScore && (
|
{ratingData?.criticsRating && !!ratingData?.criticsScore && (
|
||||||
<>
|
<Tooltip
|
||||||
<span className="media-rating">
|
content={intl.formatMessage(messages.rtcriticsscore)}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={ratingData.url}
|
||||||
|
className="media-rating"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
{ratingData.criticsRating === 'Rotten' ? (
|
{ratingData.criticsRating === 'Rotten' ? (
|
||||||
<RTRotten className="mr-1 w-6" />
|
<RTRotten className="w-6" />
|
||||||
) : (
|
) : (
|
||||||
<RTFresh className="mr-1 w-6" />
|
<RTFresh className="w-6" />
|
||||||
)}
|
)}
|
||||||
{ratingData.criticsScore}%
|
<span>{ratingData.criticsScore}%</span>
|
||||||
</span>
|
</a>
|
||||||
</>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{ratingData?.audienceRating && !!ratingData?.audienceScore && (
|
{ratingData?.audienceRating && !!ratingData?.audienceScore && (
|
||||||
<>
|
<Tooltip
|
||||||
<span className="media-rating">
|
content={intl.formatMessage(messages.rtaudiencescore)}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={ratingData.url}
|
||||||
|
className="media-rating"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
{ratingData.audienceRating === 'Spilled' ? (
|
{ratingData.audienceRating === 'Spilled' ? (
|
||||||
<RTAudRotten className="mr-1 w-6" />
|
<RTAudRotten className="w-6" />
|
||||||
) : (
|
) : (
|
||||||
<RTAudFresh className="mr-1 w-6" />
|
<RTAudFresh className="w-6" />
|
||||||
)}
|
)}
|
||||||
{ratingData.audienceScore}%
|
<span>{ratingData.audienceScore}%</span>
|
||||||
</span>
|
</a>
|
||||||
</>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{!!data.voteCount && (
|
{!!data.voteCount && (
|
||||||
<>
|
<Tooltip content={intl.formatMessage(messages.tmdbuserscore)}>
|
||||||
<span className="media-rating">
|
<a
|
||||||
<TmdbLogo className="mr-2 w-6" />
|
href={`https://www.themoviedb.org/movie/${data.id}?language=${locale}`}
|
||||||
{data.voteAverage}/10
|
className="media-rating"
|
||||||
</span>
|
target="_blank"
|
||||||
</>
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<TmdbLogo className="mr-1 w-6" />
|
||||||
|
<span>{Math.round(data.voteAverage * 10)}%</span>
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Badge from '@app/components/Common/Badge';
|
import Badge from '@app/components/Common/Badge';
|
||||||
import Button from '@app/components/Common/Button';
|
import Button from '@app/components/Common/Button';
|
||||||
|
import Tooltip from '@app/components/Common/Tooltip';
|
||||||
import RequestModal from '@app/components/RequestModal';
|
import RequestModal from '@app/components/RequestModal';
|
||||||
import useRequestOverride from '@app/hooks/useRequestOverride';
|
import useRequestOverride from '@app/hooks/useRequestOverride';
|
||||||
import { useUser } from '@app/hooks/useUser';
|
import { useUser } from '@app/hooks/useUser';
|
||||||
@@ -27,6 +28,13 @@ const messages = defineMessages({
|
|||||||
profilechanged: 'Quality Profile',
|
profilechanged: 'Quality Profile',
|
||||||
rootfolder: 'Root Folder',
|
rootfolder: 'Root Folder',
|
||||||
languageprofile: 'Language Profile',
|
languageprofile: 'Language Profile',
|
||||||
|
requestdate: 'Request Date',
|
||||||
|
requestedby: 'Requested By',
|
||||||
|
lastmodifiedby: 'Last Modified By',
|
||||||
|
approve: 'Approve Request',
|
||||||
|
decline: 'Decline Request',
|
||||||
|
edit: 'Edit Request',
|
||||||
|
delete: 'Delete Request',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface RequestBlockProps {
|
interface RequestBlockProps {
|
||||||
@@ -83,7 +91,9 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
|||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="mr-6 min-w-0 flex-1 flex-col items-center text-sm leading-5">
|
<div className="mr-6 min-w-0 flex-1 flex-col items-center text-sm leading-5">
|
||||||
<div className="white mb-1 flex flex-nowrap">
|
<div className="white mb-1 flex flex-nowrap">
|
||||||
<UserIcon className="mr-1.5 h-5 w-5 min-w-0 flex-shrink-0" />
|
<Tooltip content={intl.formatMessage(messages.requestedby)}>
|
||||||
|
<UserIcon className="mr-1.5 h-5 w-5 min-w-0 flex-shrink-0" />
|
||||||
|
</Tooltip>
|
||||||
<span className="w-40 truncate md:w-auto">
|
<span className="w-40 truncate md:w-auto">
|
||||||
<Link
|
<Link
|
||||||
href={
|
href={
|
||||||
@@ -100,7 +110,9 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
|||||||
</div>
|
</div>
|
||||||
{request.modifiedBy && (
|
{request.modifiedBy && (
|
||||||
<div className="flex flex-nowrap">
|
<div className="flex flex-nowrap">
|
||||||
<EyeIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
|
<Tooltip content={intl.formatMessage(messages.lastmodifiedby)}>
|
||||||
|
<EyeIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
|
||||||
|
</Tooltip>
|
||||||
<span className="w-40 truncate md:w-auto">
|
<span className="w-40 truncate md:w-auto">
|
||||||
<Link
|
<Link
|
||||||
href={
|
href={
|
||||||
@@ -120,39 +132,47 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
|||||||
<div className="ml-2 flex flex-shrink-0 flex-wrap">
|
<div className="ml-2 flex flex-shrink-0 flex-wrap">
|
||||||
{request.status === MediaRequestStatus.PENDING && (
|
{request.status === MediaRequestStatus.PENDING && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Tooltip content={intl.formatMessage(messages.approve)}>
|
||||||
buttonType="success"
|
<Button
|
||||||
className="mr-1"
|
buttonType="success"
|
||||||
onClick={() => updateRequest('approve')}
|
className="mr-1"
|
||||||
disabled={isUpdating}
|
onClick={() => updateRequest('approve')}
|
||||||
>
|
disabled={isUpdating}
|
||||||
<CheckIcon className="icon-sm" />
|
>
|
||||||
</Button>
|
<CheckIcon className="icon-sm" />
|
||||||
<Button
|
</Button>
|
||||||
buttonType="danger"
|
</Tooltip>
|
||||||
className="mr-1"
|
<Tooltip content={intl.formatMessage(messages.decline)}>
|
||||||
onClick={() => updateRequest('decline')}
|
<Button
|
||||||
disabled={isUpdating}
|
buttonType="danger"
|
||||||
>
|
className="mr-1"
|
||||||
<XIcon />
|
onClick={() => updateRequest('decline')}
|
||||||
</Button>
|
disabled={isUpdating}
|
||||||
<Button
|
>
|
||||||
buttonType="primary"
|
<XIcon />
|
||||||
onClick={() => setShowEditModal(true)}
|
</Button>
|
||||||
disabled={isUpdating}
|
</Tooltip>
|
||||||
>
|
<Tooltip content={intl.formatMessage(messages.edit)}>
|
||||||
<PencilIcon className="icon-sm" />
|
<Button
|
||||||
</Button>
|
buttonType="primary"
|
||||||
|
onClick={() => setShowEditModal(true)}
|
||||||
|
disabled={isUpdating}
|
||||||
|
>
|
||||||
|
<PencilIcon className="icon-sm" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{request.status !== MediaRequestStatus.PENDING && (
|
{request.status !== MediaRequestStatus.PENDING && (
|
||||||
<Button
|
<Tooltip content={intl.formatMessage(messages.delete)}>
|
||||||
buttonType="danger"
|
<Button
|
||||||
onClick={() => deleteRequest()}
|
buttonType="danger"
|
||||||
disabled={isUpdating}
|
onClick={() => deleteRequest()}
|
||||||
>
|
disabled={isUpdating}
|
||||||
<TrashIcon className="icon-sm" />
|
>
|
||||||
</Button>
|
<TrashIcon className="icon-sm" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -187,7 +207,9 @@ const RequestBlock = ({ request, onUpdate }: RequestBlockProps) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 flex items-center text-sm leading-5 sm:mt-0">
|
<div className="mt-2 flex items-center text-sm leading-5 sm:mt-0">
|
||||||
<CalendarIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
|
<Tooltip content={intl.formatMessage(messages.requestdate)}>
|
||||||
|
<CalendarIcon className="mr-1.5 h-5 w-5 flex-shrink-0" />
|
||||||
|
</Tooltip>
|
||||||
<span>
|
<span>
|
||||||
{intl.formatDate(request.createdAt, {
|
{intl.formatDate(request.createdAt, {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import Badge from '@app/components/Common/Badge';
|
import Badge from '@app/components/Common/Badge';
|
||||||
import Button from '@app/components/Common/Button';
|
import Button from '@app/components/Common/Button';
|
||||||
import CachedImage from '@app/components/Common/CachedImage';
|
import CachedImage from '@app/components/Common/CachedImage';
|
||||||
|
import Tooltip from '@app/components/Common/Tooltip';
|
||||||
import RequestModal from '@app/components/RequestModal';
|
import RequestModal from '@app/components/RequestModal';
|
||||||
import StatusBadge from '@app/components/StatusBadge';
|
import StatusBadge from '@app/components/StatusBadge';
|
||||||
import { Permission, useUser } from '@app/hooks/useUser';
|
import { Permission, useUser } from '@app/hooks/useUser';
|
||||||
@@ -31,6 +32,10 @@ const messages = defineMessages({
|
|||||||
mediaerror: '{mediaType} Not Found',
|
mediaerror: '{mediaType} Not Found',
|
||||||
tmdbid: 'TMDB ID',
|
tmdbid: 'TMDB ID',
|
||||||
tvdbid: 'TheTVDB ID',
|
tvdbid: 'TheTVDB ID',
|
||||||
|
approverequest: 'Approve Request',
|
||||||
|
declinerequest: 'Decline Request',
|
||||||
|
editrequest: 'Edit Request',
|
||||||
|
cancelrequest: 'Cancel Request',
|
||||||
deleterequest: 'Delete Request',
|
deleterequest: 'Delete Request',
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -139,11 +144,9 @@ const RequestCardError = ({ requestData }: RequestCardErrorProps) => {
|
|||||||
: requestData.media.plexUrl
|
: requestData.media.plexUrl
|
||||||
}
|
}
|
||||||
serviceUrl={
|
serviceUrl={
|
||||||
hasPermission(Permission.ADMIN)
|
requestData.is4k
|
||||||
? requestData.is4k
|
? requestData.media.serviceUrl4k
|
||||||
? requestData.media.serviceUrl4k
|
: requestData.media.serviceUrl
|
||||||
: requestData.media.serviceUrl
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -153,17 +156,29 @@ const RequestCardError = ({ requestData }: RequestCardErrorProps) => {
|
|||||||
<div className="flex flex-1 items-end space-x-2">
|
<div className="flex flex-1 items-end space-x-2">
|
||||||
{hasPermission(Permission.MANAGE_REQUESTS) &&
|
{hasPermission(Permission.MANAGE_REQUESTS) &&
|
||||||
requestData?.media.id && (
|
requestData?.media.id && (
|
||||||
<Button
|
<>
|
||||||
buttonType="danger"
|
<Button
|
||||||
buttonSize="sm"
|
buttonType="danger"
|
||||||
className="mt-4"
|
buttonSize="sm"
|
||||||
onClick={() => deleteRequest()}
|
className="mt-4 hidden sm:block"
|
||||||
>
|
onClick={() => deleteRequest()}
|
||||||
<TrashIcon style={{ marginRight: '0' }} />
|
>
|
||||||
<span className="ml-1.5 hidden sm:block">
|
<TrashIcon />
|
||||||
{intl.formatMessage(messages.deleterequest)}
|
<span>{intl.formatMessage(globalMessages.delete)}</span>
|
||||||
</span>
|
</Button>
|
||||||
</Button>
|
<Tooltip
|
||||||
|
content={intl.formatMessage(messages.deleterequest)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
buttonType="danger"
|
||||||
|
buttonSize="sm"
|
||||||
|
className="mt-4 sm:hidden"
|
||||||
|
onClick={() => deleteRequest()}
|
||||||
|
>
|
||||||
|
<TrashIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -389,7 +404,14 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
|||||||
tmdbId={requestData.media.tmdbId}
|
tmdbId={requestData.media.tmdbId}
|
||||||
mediaType={requestData.type}
|
mediaType={requestData.type}
|
||||||
plexUrl={
|
plexUrl={
|
||||||
requestData.media[requestData.is4k ? 'plexUrl4k' : 'plexUrl']
|
requestData.is4k
|
||||||
|
? requestData.media.plexUrl4k
|
||||||
|
: requestData.media.plexUrl
|
||||||
|
}
|
||||||
|
serviceUrl={
|
||||||
|
requestData.is4k
|
||||||
|
? requestData.media.serviceUrl4k
|
||||||
|
: requestData.media.serviceUrl
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -415,26 +437,52 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
|||||||
{requestData.status === MediaRequestStatus.PENDING &&
|
{requestData.status === MediaRequestStatus.PENDING &&
|
||||||
hasPermission(Permission.MANAGE_REQUESTS) && (
|
hasPermission(Permission.MANAGE_REQUESTS) && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<div>
|
||||||
buttonType="success"
|
<Button
|
||||||
buttonSize="sm"
|
buttonType="success"
|
||||||
onClick={() => modifyRequest('approve')}
|
buttonSize="sm"
|
||||||
>
|
className="hidden sm:block"
|
||||||
<CheckIcon style={{ marginRight: '0' }} />
|
onClick={() => modifyRequest('approve')}
|
||||||
<span className="ml-1.5 hidden sm:block">
|
>
|
||||||
{intl.formatMessage(globalMessages.approve)}
|
<CheckIcon />
|
||||||
</span>
|
<span>{intl.formatMessage(globalMessages.approve)}</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Tooltip
|
||||||
buttonType="danger"
|
content={intl.formatMessage(messages.approverequest)}
|
||||||
buttonSize="sm"
|
>
|
||||||
onClick={() => modifyRequest('decline')}
|
<Button
|
||||||
>
|
buttonType="success"
|
||||||
<XIcon style={{ marginRight: '0' }} />
|
buttonSize="sm"
|
||||||
<span className="ml-1.5 hidden sm:block">
|
className="sm:hidden"
|
||||||
{intl.formatMessage(globalMessages.decline)}
|
onClick={() => modifyRequest('approve')}
|
||||||
</span>
|
>
|
||||||
</Button>
|
<CheckIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
buttonType="danger"
|
||||||
|
buttonSize="sm"
|
||||||
|
className="hidden sm:block"
|
||||||
|
onClick={() => modifyRequest('decline')}
|
||||||
|
>
|
||||||
|
<XIcon />
|
||||||
|
<span>{intl.formatMessage(globalMessages.decline)}</span>
|
||||||
|
</Button>
|
||||||
|
<Tooltip
|
||||||
|
content={intl.formatMessage(messages.declinerequest)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
buttonType="danger"
|
||||||
|
buttonSize="sm"
|
||||||
|
className="sm:hidden"
|
||||||
|
onClick={() => modifyRequest('decline')}
|
||||||
|
>
|
||||||
|
<XIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{requestData.status === MediaRequestStatus.PENDING &&
|
{requestData.status === MediaRequestStatus.PENDING &&
|
||||||
@@ -442,33 +490,54 @@ const RequestCard = ({ request, onTitleData }: RequestCardProps) => {
|
|||||||
requestData.requestedBy.id === user?.id &&
|
requestData.requestedBy.id === user?.id &&
|
||||||
(requestData.type === 'tv' ||
|
(requestData.type === 'tv' ||
|
||||||
hasPermission(Permission.REQUEST_ADVANCED)) && (
|
hasPermission(Permission.REQUEST_ADVANCED)) && (
|
||||||
<Button
|
<div>
|
||||||
buttonType="primary"
|
{!hasPermission(Permission.MANAGE_REQUESTS) && (
|
||||||
buttonSize="sm"
|
<Button
|
||||||
onClick={() => setShowEditModal(true)}
|
buttonType="primary"
|
||||||
className={`${
|
buttonSize="sm"
|
||||||
hasPermission(Permission.MANAGE_REQUESTS) ? 'sm:hidden' : ''
|
className="hidden sm:block"
|
||||||
}`}
|
onClick={() => setShowEditModal(true)}
|
||||||
>
|
>
|
||||||
<PencilIcon style={{ marginRight: '0' }} />
|
<PencilIcon />
|
||||||
<span className="ml-1.5 hidden sm:block">
|
<span>{intl.formatMessage(globalMessages.edit)}</span>
|
||||||
{intl.formatMessage(globalMessages.edit)}
|
</Button>
|
||||||
</span>
|
)}
|
||||||
</Button>
|
<Tooltip content={intl.formatMessage(messages.editrequest)}>
|
||||||
|
<Button
|
||||||
|
buttonType="primary"
|
||||||
|
buttonSize="sm"
|
||||||
|
className="sm:hidden"
|
||||||
|
onClick={() => setShowEditModal(true)}
|
||||||
|
>
|
||||||
|
<PencilIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{requestData.status === MediaRequestStatus.PENDING &&
|
{requestData.status === MediaRequestStatus.PENDING &&
|
||||||
!hasPermission(Permission.MANAGE_REQUESTS) &&
|
!hasPermission(Permission.MANAGE_REQUESTS) &&
|
||||||
requestData.requestedBy.id === user?.id && (
|
requestData.requestedBy.id === user?.id && (
|
||||||
<Button
|
<div>
|
||||||
buttonType="danger"
|
<Button
|
||||||
buttonSize="sm"
|
buttonType="danger"
|
||||||
onClick={() => deleteRequest()}
|
buttonSize="sm"
|
||||||
>
|
className="hidden sm:block"
|
||||||
<XIcon style={{ marginRight: '0' }} />
|
onClick={() => deleteRequest()}
|
||||||
<span className="ml-1.5 hidden sm:block">
|
>
|
||||||
{intl.formatMessage(globalMessages.cancel)}
|
<XIcon />
|
||||||
</span>
|
<span>{intl.formatMessage(globalMessages.cancel)}</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
<Tooltip content={intl.formatMessage(messages.cancelrequest)}>
|
||||||
|
<Button
|
||||||
|
buttonType="danger"
|
||||||
|
buttonSize="sm"
|
||||||
|
className="sm:hidden"
|
||||||
|
onClick={() => deleteRequest()}
|
||||||
|
>
|
||||||
|
<XIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -136,11 +136,9 @@ const RequestItemError = ({
|
|||||||
: requestData.media.plexUrl
|
: requestData.media.plexUrl
|
||||||
}
|
}
|
||||||
serviceUrl={
|
serviceUrl={
|
||||||
hasPermission(Permission.ADMIN)
|
requestData.is4k
|
||||||
? requestData.is4k
|
? requestData.media.serviceUrl4k
|
||||||
? requestData.media.serviceUrl4k
|
: requestData.media.serviceUrl
|
||||||
: requestData.media.serviceUrl
|
|
||||||
: undefined
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -472,9 +470,14 @@ const RequestItem = ({ request, revalidateList }: RequestItemProps) => {
|
|||||||
tmdbId={requestData.media.tmdbId}
|
tmdbId={requestData.media.tmdbId}
|
||||||
mediaType={requestData.type}
|
mediaType={requestData.type}
|
||||||
plexUrl={
|
plexUrl={
|
||||||
requestData.media[
|
requestData.is4k
|
||||||
requestData.is4k ? 'plexUrl4k' : 'plexUrl'
|
? requestData.media.plexUrl4k
|
||||||
]
|
: requestData.media.plexUrl
|
||||||
|
}
|
||||||
|
serviceUrl={
|
||||||
|
requestData.is4k
|
||||||
|
? requestData.media.serviceUrl4k
|
||||||
|
: requestData.media.serviceUrl
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const messages = defineMessages({
|
|||||||
'Do NOT enable this setting unless you understand what you are doing!',
|
'Do NOT enable this setting unless you understand what you are doing!',
|
||||||
cacheImages: 'Enable Image Caching',
|
cacheImages: 'Enable Image Caching',
|
||||||
cacheImagesTip:
|
cacheImagesTip:
|
||||||
'Optimize and store all images locally (consumes a significant amount of disk space)',
|
'Cache and serve optimized images (requires a significant amount of disk space)',
|
||||||
trustProxy: 'Enable Proxy Support',
|
trustProxy: 'Enable Proxy Support',
|
||||||
trustProxyTip:
|
trustProxyTip:
|
||||||
'Allow Overseerr to correctly register client IP addresses behind a proxy',
|
'Allow Overseerr to correctly register client IP addresses behind a proxy',
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import Spinner from '@app/assets/spinner.svg';
|
import Spinner from '@app/assets/spinner.svg';
|
||||||
import Badge from '@app/components/Common/Badge';
|
import Badge from '@app/components/Common/Badge';
|
||||||
|
import Tooltip from '@app/components/Common/Tooltip';
|
||||||
import useSettings from '@app/hooks/useSettings';
|
import useSettings from '@app/hooks/useSettings';
|
||||||
import { Permission, useUser } from '@app/hooks/useUser';
|
import { Permission, useUser } from '@app/hooks/useUser';
|
||||||
import globalMessages from '@app/i18n/globalMessages';
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
@@ -9,6 +10,9 @@ import { defineMessages, useIntl } from 'react-intl';
|
|||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
status: '{status}',
|
status: '{status}',
|
||||||
status4k: '4K {status}',
|
status4k: '4K {status}',
|
||||||
|
playonplex: 'Play on Plex',
|
||||||
|
openinarr: 'Open in {arr}',
|
||||||
|
managemedia: 'Manage {mediaType}',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface StatusBadgeProps {
|
interface StatusBadgeProps {
|
||||||
@@ -35,6 +39,7 @@ const StatusBadge = ({
|
|||||||
const settings = useSettings();
|
const settings = useSettings();
|
||||||
|
|
||||||
let mediaLink: string | undefined;
|
let mediaLink: string | undefined;
|
||||||
|
let mediaLinkDescription: string | undefined;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
mediaType &&
|
mediaType &&
|
||||||
@@ -63,63 +68,94 @@ const StatusBadge = ({
|
|||||||
: settings.currentSettings.series4kEnabled))
|
: settings.currentSettings.series4kEnabled))
|
||||||
) {
|
) {
|
||||||
mediaLink = plexUrl;
|
mediaLink = plexUrl;
|
||||||
|
mediaLinkDescription = intl.formatMessage(messages.playonplex);
|
||||||
} else if (hasPermission(Permission.MANAGE_REQUESTS)) {
|
} else if (hasPermission(Permission.MANAGE_REQUESTS)) {
|
||||||
mediaLink =
|
if (mediaType && tmdbId) {
|
||||||
mediaType && tmdbId ? `/${mediaType}/${tmdbId}?manage=1` : serviceUrl;
|
mediaLink = `/${mediaType}/${tmdbId}?manage=1`;
|
||||||
|
mediaLinkDescription = intl.formatMessage(messages.managemedia, {
|
||||||
|
mediaType: intl.formatMessage(
|
||||||
|
mediaType === 'movie' ? globalMessages.movie : globalMessages.tvshow
|
||||||
|
),
|
||||||
|
});
|
||||||
|
} else if (hasPermission(Permission.ADMIN)) {
|
||||||
|
mediaLink = serviceUrl;
|
||||||
|
mediaLinkDescription = intl.formatMessage(messages.openinarr, {
|
||||||
|
arr: mediaType === 'movie' ? 'Radarr' : 'Sonarr',
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case MediaStatus.AVAILABLE:
|
case MediaStatus.AVAILABLE:
|
||||||
return (
|
return (
|
||||||
<Badge badgeType="success" href={mediaLink}>
|
<Tooltip content={mediaLinkDescription}>
|
||||||
<div className="flex items-center">
|
<Badge badgeType="success" href={mediaLink}>
|
||||||
<span>
|
<div className="flex items-center">
|
||||||
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
|
<span>
|
||||||
status: intl.formatMessage(globalMessages.available),
|
{intl.formatMessage(
|
||||||
})}
|
is4k ? messages.status4k : messages.status,
|
||||||
</span>
|
{
|
||||||
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
|
status: intl.formatMessage(globalMessages.available),
|
||||||
</div>
|
}
|
||||||
</Badge>
|
)}
|
||||||
|
</span>
|
||||||
|
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
|
||||||
|
</div>
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|
||||||
case MediaStatus.PARTIALLY_AVAILABLE:
|
case MediaStatus.PARTIALLY_AVAILABLE:
|
||||||
return (
|
return (
|
||||||
<Badge badgeType="success" href={mediaLink}>
|
<Tooltip content={mediaLinkDescription}>
|
||||||
<div className="flex items-center">
|
<Badge badgeType="success" href={mediaLink}>
|
||||||
<span>
|
<div className="flex items-center">
|
||||||
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
|
<span>
|
||||||
status: intl.formatMessage(globalMessages.partiallyavailable),
|
{intl.formatMessage(
|
||||||
})}
|
is4k ? messages.status4k : messages.status,
|
||||||
</span>
|
{
|
||||||
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
|
status: intl.formatMessage(
|
||||||
</div>
|
globalMessages.partiallyavailable
|
||||||
</Badge>
|
),
|
||||||
|
}
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
|
||||||
|
</div>
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|
||||||
case MediaStatus.PROCESSING:
|
case MediaStatus.PROCESSING:
|
||||||
return (
|
return (
|
||||||
<Badge badgeType="primary" href={mediaLink}>
|
<Tooltip content={mediaLinkDescription}>
|
||||||
<div className="flex items-center">
|
<Badge badgeType="primary" href={mediaLink}>
|
||||||
<span>
|
<div className="flex items-center">
|
||||||
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
|
<span>
|
||||||
status: inProgress
|
{intl.formatMessage(
|
||||||
? intl.formatMessage(globalMessages.processing)
|
is4k ? messages.status4k : messages.status,
|
||||||
: intl.formatMessage(globalMessages.requested),
|
{
|
||||||
})}
|
status: inProgress
|
||||||
</span>
|
? intl.formatMessage(globalMessages.processing)
|
||||||
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
|
: intl.formatMessage(globalMessages.requested),
|
||||||
</div>
|
}
|
||||||
</Badge>
|
)}
|
||||||
|
</span>
|
||||||
|
{inProgress && <Spinner className="ml-1 h-3 w-3" />}
|
||||||
|
</div>
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|
||||||
case MediaStatus.PENDING:
|
case MediaStatus.PENDING:
|
||||||
return (
|
return (
|
||||||
<Badge badgeType="warning" href={mediaLink}>
|
<Tooltip content={mediaLinkDescription}>
|
||||||
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
|
<Badge badgeType="warning" href={mediaLink}>
|
||||||
status: intl.formatMessage(globalMessages.pending),
|
{intl.formatMessage(is4k ? messages.status4k : messages.status, {
|
||||||
})}
|
status: intl.formatMessage(globalMessages.pending),
|
||||||
</Badge>
|
})}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
);
|
);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -79,6 +79,9 @@ const messages = defineMessages({
|
|||||||
episodeCount: '{episodeCount, plural, one {# Episode} other {# Episodes}}',
|
episodeCount: '{episodeCount, plural, one {# Episode} other {# Episodes}}',
|
||||||
seasonnumber: 'Season {seasonNumber}',
|
seasonnumber: 'Season {seasonNumber}',
|
||||||
status4k: '4K {status}',
|
status4k: '4K {status}',
|
||||||
|
rtcriticsscore: 'Rotten Tomatoes Tomatometer',
|
||||||
|
rtaudiencescore: 'Rotten Tomatoes Audience Score',
|
||||||
|
tmdbuserscore: 'TMDB User Score',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface TvDetailsProps {
|
interface TvDetailsProps {
|
||||||
@@ -330,6 +333,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
|||||||
tmdbId={data.mediaInfo?.tmdbId}
|
tmdbId={data.mediaInfo?.tmdbId}
|
||||||
mediaType="tv"
|
mediaType="tv"
|
||||||
plexUrl={data.mediaInfo?.plexUrl}
|
plexUrl={data.mediaInfo?.plexUrl}
|
||||||
|
serviceUrl={data.mediaInfo?.serviceUrl}
|
||||||
/>
|
/>
|
||||||
{settings.currentSettings.series4kEnabled &&
|
{settings.currentSettings.series4kEnabled &&
|
||||||
hasPermission(
|
hasPermission(
|
||||||
@@ -351,6 +355,7 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
|||||||
tmdbId={data.mediaInfo?.tmdbId}
|
tmdbId={data.mediaInfo?.tmdbId}
|
||||||
mediaType="tv"
|
mediaType="tv"
|
||||||
plexUrl={data.mediaInfo?.plexUrl4k}
|
plexUrl={data.mediaInfo?.plexUrl4k}
|
||||||
|
serviceUrl={data.mediaInfo?.serviceUrl4k}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -660,30 +665,55 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
|||||||
(ratingData?.audienceRating && !!ratingData?.audienceScore)) && (
|
(ratingData?.audienceRating && !!ratingData?.audienceScore)) && (
|
||||||
<div className="media-ratings">
|
<div className="media-ratings">
|
||||||
{ratingData?.criticsRating && !!ratingData?.criticsScore && (
|
{ratingData?.criticsRating && !!ratingData?.criticsScore && (
|
||||||
<span className="media-rating">
|
<Tooltip
|
||||||
{ratingData.criticsRating === 'Rotten' ? (
|
content={intl.formatMessage(messages.rtcriticsscore)}
|
||||||
<RTRotten className="mr-1 w-6" />
|
>
|
||||||
) : (
|
<a
|
||||||
<RTFresh className="mr-1 w-6" />
|
href={ratingData.url}
|
||||||
)}
|
className="media-rating"
|
||||||
{ratingData.criticsScore}%
|
target="_blank"
|
||||||
</span>
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{ratingData.criticsRating === 'Rotten' ? (
|
||||||
|
<RTRotten className="mr-1 w-6" />
|
||||||
|
) : (
|
||||||
|
<RTFresh className="mr-1 w-6" />
|
||||||
|
)}
|
||||||
|
<span>{ratingData.criticsScore}%</span>
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{ratingData?.audienceRating && !!ratingData?.audienceScore && (
|
{ratingData?.audienceRating && !!ratingData?.audienceScore && (
|
||||||
<span className="media-rating">
|
<Tooltip
|
||||||
{ratingData.audienceRating === 'Spilled' ? (
|
content={intl.formatMessage(messages.rtaudiencescore)}
|
||||||
<RTAudRotten className="mr-1 w-6" />
|
>
|
||||||
) : (
|
<a
|
||||||
<RTAudFresh className="mr-1 w-6" />
|
href={ratingData.url}
|
||||||
)}
|
className="media-rating"
|
||||||
{ratingData.audienceScore}%
|
target="_blank"
|
||||||
</span>
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{ratingData.audienceRating === 'Spilled' ? (
|
||||||
|
<RTAudRotten className="mr-1 w-6" />
|
||||||
|
) : (
|
||||||
|
<RTAudFresh className="mr-1 w-6" />
|
||||||
|
)}
|
||||||
|
<span>{ratingData.audienceScore}%</span>
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{!!data.voteCount && (
|
{!!data.voteCount && (
|
||||||
<span className="media-rating">
|
<Tooltip content={intl.formatMessage(messages.tmdbuserscore)}>
|
||||||
<TmdbLogo className="mr-2 w-6" />
|
<a
|
||||||
{data.voteAverage}/10
|
href={`https://www.themoviedb.org/tv/${data.id}?language=${locale}`}
|
||||||
</span>
|
className="media-rating"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
<TmdbLogo className="mr-1 w-6" />
|
||||||
|
<span>{Math.round(data.voteAverage * 10)}%</span>
|
||||||
|
</a>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -181,6 +181,8 @@
|
|||||||
"components.MovieDetails.releasedate": "{releaseCount, plural, one {Release Date} other {Release Dates}}",
|
"components.MovieDetails.releasedate": "{releaseCount, plural, one {Release Date} other {Release Dates}}",
|
||||||
"components.MovieDetails.reportissue": "Report an Issue",
|
"components.MovieDetails.reportissue": "Report an Issue",
|
||||||
"components.MovieDetails.revenue": "Revenue",
|
"components.MovieDetails.revenue": "Revenue",
|
||||||
|
"components.MovieDetails.rtaudiencescore": "Rotten Tomatoes Audience Score",
|
||||||
|
"components.MovieDetails.rtcriticsscore": "Rotten Tomatoes Tomatometer",
|
||||||
"components.MovieDetails.runtime": "{minutes} minutes",
|
"components.MovieDetails.runtime": "{minutes} minutes",
|
||||||
"components.MovieDetails.showless": "Show Less",
|
"components.MovieDetails.showless": "Show Less",
|
||||||
"components.MovieDetails.showmore": "Show More",
|
"components.MovieDetails.showmore": "Show More",
|
||||||
@@ -188,6 +190,7 @@
|
|||||||
"components.MovieDetails.streamingproviders": "Currently Streaming On",
|
"components.MovieDetails.streamingproviders": "Currently Streaming On",
|
||||||
"components.MovieDetails.studio": "{studioCount, plural, one {Studio} other {Studios}}",
|
"components.MovieDetails.studio": "{studioCount, plural, one {Studio} other {Studios}}",
|
||||||
"components.MovieDetails.theatricalrelease": "Theatrical Release",
|
"components.MovieDetails.theatricalrelease": "Theatrical Release",
|
||||||
|
"components.MovieDetails.tmdbuserscore": "TMDB User Score",
|
||||||
"components.MovieDetails.viewfullcrew": "View Full Crew",
|
"components.MovieDetails.viewfullcrew": "View Full Crew",
|
||||||
"components.MovieDetails.watchtrailer": "Watch Trailer",
|
"components.MovieDetails.watchtrailer": "Watch Trailer",
|
||||||
"components.NotificationTypeSelector.adminissuecommentDescription": "Get notified when other users comment on issues.",
|
"components.NotificationTypeSelector.adminissuecommentDescription": "Get notified when other users comment on issues.",
|
||||||
@@ -292,8 +295,15 @@
|
|||||||
"components.QuotaSelector.unlimited": "Unlimited",
|
"components.QuotaSelector.unlimited": "Unlimited",
|
||||||
"components.RegionSelector.regionDefault": "All Regions",
|
"components.RegionSelector.regionDefault": "All Regions",
|
||||||
"components.RegionSelector.regionServerDefault": "Default ({region})",
|
"components.RegionSelector.regionServerDefault": "Default ({region})",
|
||||||
|
"components.RequestBlock.approve": "Approve Request",
|
||||||
|
"components.RequestBlock.decline": "Decline Request",
|
||||||
|
"components.RequestBlock.delete": "Delete Request",
|
||||||
|
"components.RequestBlock.edit": "Edit Request",
|
||||||
"components.RequestBlock.languageprofile": "Language Profile",
|
"components.RequestBlock.languageprofile": "Language Profile",
|
||||||
|
"components.RequestBlock.lastmodifiedby": "Last Modified By",
|
||||||
"components.RequestBlock.profilechanged": "Quality Profile",
|
"components.RequestBlock.profilechanged": "Quality Profile",
|
||||||
|
"components.RequestBlock.requestdate": "Request Date",
|
||||||
|
"components.RequestBlock.requestedby": "Requested By",
|
||||||
"components.RequestBlock.requestoverrides": "Request Overrides",
|
"components.RequestBlock.requestoverrides": "Request Overrides",
|
||||||
"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}}",
|
||||||
@@ -310,7 +320,11 @@
|
|||||||
"components.RequestButton.requestmore4k": "Request More in 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.approverequest": "Approve Request",
|
||||||
|
"components.RequestCard.cancelrequest": "Cancel Request",
|
||||||
|
"components.RequestCard.declinerequest": "Decline Request",
|
||||||
"components.RequestCard.deleterequest": "Delete Request",
|
"components.RequestCard.deleterequest": "Delete Request",
|
||||||
|
"components.RequestCard.editrequest": "Edit Request",
|
||||||
"components.RequestCard.failedretry": "Something went wrong while retrying the request.",
|
"components.RequestCard.failedretry": "Something went wrong while retrying the request.",
|
||||||
"components.RequestCard.mediaerror": "{mediaType} Not Found",
|
"components.RequestCard.mediaerror": "{mediaType} Not Found",
|
||||||
"components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
|
"components.RequestCard.seasons": "{seasonCount, plural, one {Season} other {Seasons}}",
|
||||||
@@ -736,7 +750,7 @@
|
|||||||
"components.Settings.applicationTitle": "Application Title",
|
"components.Settings.applicationTitle": "Application Title",
|
||||||
"components.Settings.applicationurl": "Application URL",
|
"components.Settings.applicationurl": "Application URL",
|
||||||
"components.Settings.cacheImages": "Enable Image Caching",
|
"components.Settings.cacheImages": "Enable Image Caching",
|
||||||
"components.Settings.cacheImagesTip": "Optimize and store all images locally (consumes a significant amount of disk space)",
|
"components.Settings.cacheImagesTip": "Cache and serve optimized images (requires a significant amount of disk space)",
|
||||||
"components.Settings.cancelscan": "Cancel Scan",
|
"components.Settings.cancelscan": "Cancel Scan",
|
||||||
"components.Settings.copied": "Copied API key to clipboard.",
|
"components.Settings.copied": "Copied API key to clipboard.",
|
||||||
"components.Settings.csrfProtection": "Enable CSRF Protection",
|
"components.Settings.csrfProtection": "Enable CSRF Protection",
|
||||||
@@ -849,6 +863,9 @@
|
|||||||
"components.Setup.signinMessage": "Get started by signing in with your Plex account",
|
"components.Setup.signinMessage": "Get started by signing in with your Plex account",
|
||||||
"components.Setup.tip": "Tip",
|
"components.Setup.tip": "Tip",
|
||||||
"components.Setup.welcome": "Welcome to Overseerr",
|
"components.Setup.welcome": "Welcome to Overseerr",
|
||||||
|
"components.StatusBadge.managemedia": "Manage {mediaType}",
|
||||||
|
"components.StatusBadge.openinarr": "Open in {arr}",
|
||||||
|
"components.StatusBadge.playonplex": "Play on Plex",
|
||||||
"components.StatusBadge.status": "{status}",
|
"components.StatusBadge.status": "{status}",
|
||||||
"components.StatusBadge.status4k": "4K {status}",
|
"components.StatusBadge.status4k": "4K {status}",
|
||||||
"components.StatusChecker.appUpdated": "{applicationTitle} Updated",
|
"components.StatusChecker.appUpdated": "{applicationTitle} Updated",
|
||||||
@@ -881,6 +898,8 @@
|
|||||||
"components.TvDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}",
|
"components.TvDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}",
|
||||||
"components.TvDetails.recommendations": "Recommendations",
|
"components.TvDetails.recommendations": "Recommendations",
|
||||||
"components.TvDetails.reportissue": "Report an Issue",
|
"components.TvDetails.reportissue": "Report an Issue",
|
||||||
|
"components.TvDetails.rtaudiencescore": "Rotten Tomatoes Audience Score",
|
||||||
|
"components.TvDetails.rtcriticsscore": "Rotten Tomatoes Tomatometer",
|
||||||
"components.TvDetails.seasonnumber": "Season {seasonNumber}",
|
"components.TvDetails.seasonnumber": "Season {seasonNumber}",
|
||||||
"components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}",
|
"components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}",
|
||||||
"components.TvDetails.seasonstitle": "Seasons",
|
"components.TvDetails.seasonstitle": "Seasons",
|
||||||
@@ -888,6 +907,7 @@
|
|||||||
"components.TvDetails.similar": "Similar Series",
|
"components.TvDetails.similar": "Similar Series",
|
||||||
"components.TvDetails.status4k": "4K {status}",
|
"components.TvDetails.status4k": "4K {status}",
|
||||||
"components.TvDetails.streamingproviders": "Currently Streaming On",
|
"components.TvDetails.streamingproviders": "Currently Streaming On",
|
||||||
|
"components.TvDetails.tmdbuserscore": "TMDB User Score",
|
||||||
"components.TvDetails.viewfullcrew": "View Full Crew",
|
"components.TvDetails.viewfullcrew": "View Full Crew",
|
||||||
"components.TvDetails.watchtrailer": "Watch Trailer",
|
"components.TvDetails.watchtrailer": "Watch Trailer",
|
||||||
"components.UserList.accounttype": "Type",
|
"components.UserList.accounttype": "Type",
|
||||||
|
|||||||
@@ -184,11 +184,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.media-ratings {
|
.media-ratings {
|
||||||
@apply flex items-center justify-center border-b border-gray-700 px-4 py-2 font-medium last:border-b-0;
|
@apply flex items-center justify-center space-x-5 border-b border-gray-700 px-4 py-2 font-medium last:border-b-0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.media-rating {
|
.media-rating {
|
||||||
@apply mr-4 flex items-center last:mr-0;
|
@apply flex items-center space-x-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-message {
|
.error-message {
|
||||||
|
|||||||
Reference in New Issue
Block a user