feat(frontend): add more tooltips (#2961)
* feat(frontend): add more tooltips * fix: remove styling from Tooltip * refactor: tooltip expects a single child
This commit is contained in:
@@ -1,29 +1,31 @@
|
|||||||
|
import React from 'react';
|
||||||
import type { Config } from 'react-popper-tooltip';
|
import type { Config } from 'react-popper-tooltip';
|
||||||
import { usePopperTooltip } from 'react-popper-tooltip';
|
import { usePopperTooltip } from 'react-popper-tooltip';
|
||||||
|
|
||||||
type TooltipProps = {
|
type TooltipProps = {
|
||||||
content: React.ReactNode;
|
content: React.ReactNode;
|
||||||
children: React.ReactNode;
|
children: React.ReactElement;
|
||||||
tooltipConfig?: Config;
|
tooltipConfig?: Partial<Config>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const Tooltip = ({ children, content, tooltipConfig }: TooltipProps) => {
|
const Tooltip = ({ children, content, tooltipConfig }: TooltipProps) => {
|
||||||
const { getTooltipProps, setTooltipRef, setTriggerRef, visible } =
|
const { getTooltipProps, setTooltipRef, setTriggerRef, visible } =
|
||||||
usePopperTooltip({
|
usePopperTooltip({
|
||||||
followCursor: true,
|
followCursor: true,
|
||||||
placement: 'left-end',
|
offset: [-28, 6],
|
||||||
|
placement: 'auto-end',
|
||||||
...tooltipConfig,
|
...tooltipConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div ref={setTriggerRef}>{children}</div>
|
{React.cloneElement(children, { ref: setTriggerRef })}
|
||||||
{visible && (
|
{visible && (
|
||||||
<div
|
<div
|
||||||
ref={setTooltipRef}
|
ref={setTooltipRef}
|
||||||
{...getTooltipProps({
|
{...getTooltipProps({
|
||||||
className:
|
className:
|
||||||
'bg-gray-800 px-2 py-1 rounded border border-gray-600 shadow text-gray-100',
|
'z-50 text-sm font-normal bg-gray-800 px-2 py-1 rounded border border-gray-600 shadow text-gray-100',
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{content}
|
{content}
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ const messages = defineMessages({
|
|||||||
theatricalrelease: 'Theatrical Release',
|
theatricalrelease: 'Theatrical Release',
|
||||||
digitalrelease: 'Digital Release',
|
digitalrelease: 'Digital Release',
|
||||||
physicalrelease: 'Physical Release',
|
physicalrelease: 'Physical Release',
|
||||||
|
reportissue: 'Report an Issue',
|
||||||
|
managemovie: 'Manage Movie',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface MovieDetailsProps {
|
interface MovieDetailsProps {
|
||||||
@@ -388,38 +390,42 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => {
|
|||||||
type: 'or',
|
type: 'or',
|
||||||
}
|
}
|
||||||
) && (
|
) && (
|
||||||
<Button
|
<Tooltip content={intl.formatMessage(messages.reportissue)}>
|
||||||
buttonType="warning"
|
<Button
|
||||||
className="ml-2 first:ml-0"
|
buttonType="warning"
|
||||||
onClick={() => setShowIssueModal(true)}
|
onClick={() => setShowIssueModal(true)}
|
||||||
>
|
className="ml-2 first:ml-0"
|
||||||
<ExclamationIcon />
|
>
|
||||||
</Button>
|
<ExclamationIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && (
|
{hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && (
|
||||||
<Button
|
<Tooltip content={intl.formatMessage(messages.managemovie)}>
|
||||||
buttonType="default"
|
<Button
|
||||||
className="relative ml-2 first:ml-0"
|
buttonType="default"
|
||||||
onClick={() => setShowManager(true)}
|
onClick={() => setShowManager(true)}
|
||||||
>
|
className="relative ml-2 first:ml-0"
|
||||||
<CogIcon className="!mr-0" />
|
>
|
||||||
{hasPermission(
|
<CogIcon className="!mr-0" />
|
||||||
[Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],
|
{hasPermission(
|
||||||
{
|
[Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],
|
||||||
type: 'or',
|
{
|
||||||
}
|
type: 'or',
|
||||||
) &&
|
}
|
||||||
(
|
) &&
|
||||||
data.mediaInfo?.issues.filter(
|
(
|
||||||
(issue) => issue.status === IssueStatus.OPEN
|
data.mediaInfo?.issues.filter(
|
||||||
) ?? []
|
(issue) => issue.status === IssueStatus.OPEN
|
||||||
).length > 0 && (
|
) ?? []
|
||||||
<>
|
).length > 0 && (
|
||||||
<div className="absolute -right-1 -top-1 h-3 w-3 rounded-full bg-red-600" />
|
<>
|
||||||
<div className="absolute -right-1 -top-1 h-3 w-3 animate-ping rounded-full bg-red-600" />
|
<div className="absolute -right-1 -top-1 h-3 w-3 rounded-full bg-red-600" />
|
||||||
</>
|
<div className="absolute -right-1 -top-1 h-3 w-3 animate-ping rounded-full bg-red-600" />
|
||||||
)}
|
</>
|
||||||
</Button>
|
)}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Badge from '@app/components/Common/Badge';
|
|
||||||
import Button from '@app/components/Common/Button';
|
import Button from '@app/components/Common/Button';
|
||||||
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
||||||
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
||||||
|
import SettingsBadge from '@app/components/Settings/SettingsBadge';
|
||||||
import globalMessages from '@app/i18n/globalMessages';
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
import { BeakerIcon, SaveIcon } from '@heroicons/react/outline';
|
import { BeakerIcon, SaveIcon } from '@heroicons/react/outline';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
@@ -382,9 +382,7 @@ const NotificationsEmail = () => {
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
{intl.formatMessage(messages.pgpPrivateKey)}
|
{intl.formatMessage(messages.pgpPrivateKey)}
|
||||||
</span>
|
</span>
|
||||||
<Badge badgeType="danger">
|
<SettingsBadge badgeType="advanced" />
|
||||||
{intl.formatMessage(globalMessages.advanced)}
|
|
||||||
</Badge>
|
|
||||||
<span className="label-tip">
|
<span className="label-tip">
|
||||||
{intl.formatMessage(messages.pgpPrivateKeyTip, {
|
{intl.formatMessage(messages.pgpPrivateKeyTip, {
|
||||||
OpenPgpLink: OpenPgpLink,
|
OpenPgpLink: OpenPgpLink,
|
||||||
@@ -414,9 +412,7 @@ const NotificationsEmail = () => {
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
{intl.formatMessage(messages.pgpPassword)}
|
{intl.formatMessage(messages.pgpPassword)}
|
||||||
</span>
|
</span>
|
||||||
<Badge badgeType="danger">
|
<SettingsBadge badgeType="advanced" />
|
||||||
{intl.formatMessage(globalMessages.advanced)}
|
|
||||||
</Badge>
|
|
||||||
<span className="label-tip">
|
<span className="label-tip">
|
||||||
{intl.formatMessage(messages.pgpPasswordTip, {
|
{intl.formatMessage(messages.pgpPasswordTip, {
|
||||||
OpenPgpLink: OpenPgpLink,
|
OpenPgpLink: OpenPgpLink,
|
||||||
|
|||||||
54
src/components/Settings/SettingsBadge.tsx
Normal file
54
src/components/Settings/SettingsBadge.tsx
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import Badge from '@app/components/Common/Badge';
|
||||||
|
import Tooltip from '@app/components/Common/Tooltip';
|
||||||
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
|
import { defineMessages, useIntl } from 'react-intl';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
advancedTooltip:
|
||||||
|
'Incorrectly configuring this setting may result in broken functionality',
|
||||||
|
experimentalTooltip:
|
||||||
|
'Enabling this setting may result in unexpected application behavior',
|
||||||
|
restartrequiredTooltip:
|
||||||
|
'Overseerr must be restarted for changes to this setting to take effect',
|
||||||
|
});
|
||||||
|
|
||||||
|
const SettingsBadge = ({
|
||||||
|
badgeType,
|
||||||
|
className,
|
||||||
|
}: {
|
||||||
|
badgeType: 'advanced' | 'experimental' | 'restartRequired';
|
||||||
|
className?: string;
|
||||||
|
}) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
|
||||||
|
switch (badgeType) {
|
||||||
|
case 'advanced':
|
||||||
|
return (
|
||||||
|
<Tooltip content={intl.formatMessage(messages.advancedTooltip)}>
|
||||||
|
<Badge badgeType="danger" className={className}>
|
||||||
|
{intl.formatMessage(globalMessages.advanced)}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
case 'experimental':
|
||||||
|
return (
|
||||||
|
<Tooltip content={intl.formatMessage(messages.experimentalTooltip)}>
|
||||||
|
<Badge badgeType="warning">
|
||||||
|
{intl.formatMessage(globalMessages.experimental)}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
case 'restartRequired':
|
||||||
|
return (
|
||||||
|
<Tooltip content={intl.formatMessage(messages.restartrequiredTooltip)}>
|
||||||
|
<Badge badgeType="primary" className={className}>
|
||||||
|
{intl.formatMessage(globalMessages.restartRequired)}
|
||||||
|
</Badge>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default SettingsBadge;
|
||||||
@@ -4,6 +4,7 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
|||||||
import Modal from '@app/components/Common/Modal';
|
import Modal from '@app/components/Common/Modal';
|
||||||
import PageTitle from '@app/components/Common/PageTitle';
|
import PageTitle from '@app/components/Common/PageTitle';
|
||||||
import Table from '@app/components/Common/Table';
|
import Table from '@app/components/Common/Table';
|
||||||
|
import Tooltip from '@app/components/Common/Tooltip';
|
||||||
import Transition from '@app/components/Transition';
|
import Transition from '@app/components/Transition';
|
||||||
import { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';
|
import { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams';
|
||||||
import globalMessages from '@app/i18n/globalMessages';
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
@@ -47,6 +48,7 @@ const messages = defineMessages({
|
|||||||
logDetails: 'Log Details',
|
logDetails: 'Log Details',
|
||||||
extraData: 'Additional Data',
|
extraData: 'Additional Data',
|
||||||
copiedLogMessage: 'Copied log message to clipboard.',
|
copiedLogMessage: 'Copied log message to clipboard.',
|
||||||
|
viewdetails: 'View Details',
|
||||||
});
|
});
|
||||||
|
|
||||||
type Filter = 'debug' | 'info' | 'warn' | 'error';
|
type Filter = 'debug' | 'info' | 'warn' | 'error';
|
||||||
@@ -327,23 +329,31 @@ const SettingsLogs = () => {
|
|||||||
<Table.TD className="text-gray-300">{row.message}</Table.TD>
|
<Table.TD className="text-gray-300">{row.message}</Table.TD>
|
||||||
<Table.TD className="-m-1 flex flex-wrap items-center justify-end">
|
<Table.TD className="-m-1 flex flex-wrap items-center justify-end">
|
||||||
{row.data && (
|
{row.data && (
|
||||||
|
<Tooltip
|
||||||
|
content={intl.formatMessage(messages.viewdetails)}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
buttonType="primary"
|
||||||
|
buttonSize="sm"
|
||||||
|
onClick={() => setActiveLog(row)}
|
||||||
|
className="m-1"
|
||||||
|
>
|
||||||
|
<DocumentSearchIcon className="icon-md" />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
<Tooltip
|
||||||
|
content={intl.formatMessage(messages.copyToClipboard)}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
buttonType="primary"
|
buttonType="primary"
|
||||||
buttonSize="sm"
|
buttonSize="sm"
|
||||||
onClick={() => setActiveLog(row)}
|
onClick={() => copyLogString(row)}
|
||||||
className="m-1"
|
className="m-1"
|
||||||
>
|
>
|
||||||
<DocumentSearchIcon className="icon-md" />
|
<ClipboardCopyIcon className="icon-md" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</Tooltip>
|
||||||
<Button
|
|
||||||
buttonType="primary"
|
|
||||||
buttonSize="sm"
|
|
||||||
onClick={() => copyLogString(row)}
|
|
||||||
className="m-1"
|
|
||||||
>
|
|
||||||
<ClipboardCopyIcon className="icon-md" />
|
|
||||||
</Button>
|
|
||||||
</Table.TD>
|
</Table.TD>
|
||||||
</tr>
|
</tr>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import Badge from '@app/components/Common/Badge';
|
|
||||||
import Button from '@app/components/Common/Button';
|
import Button from '@app/components/Common/Button';
|
||||||
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
||||||
import PageTitle from '@app/components/Common/PageTitle';
|
import PageTitle from '@app/components/Common/PageTitle';
|
||||||
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
||||||
|
import Tooltip from '@app/components/Common/Tooltip';
|
||||||
import LanguageSelector from '@app/components/LanguageSelector';
|
import LanguageSelector from '@app/components/LanguageSelector';
|
||||||
import RegionSelector from '@app/components/RegionSelector';
|
import RegionSelector from '@app/components/RegionSelector';
|
||||||
import CopyButton from '@app/components/Settings/CopyButton';
|
import CopyButton from '@app/components/Settings/CopyButton';
|
||||||
|
import SettingsBadge from '@app/components/Settings/SettingsBadge';
|
||||||
import type { AvailableLocale } from '@app/context/LanguageContext';
|
import type { AvailableLocale } from '@app/context/LanguageContext';
|
||||||
import { availableLanguages } from '@app/context/LanguageContext';
|
import { availableLanguages } from '@app/context/LanguageContext';
|
||||||
import useLocale from '@app/hooks/useLocale';
|
import useLocale from '@app/hooks/useLocale';
|
||||||
@@ -258,9 +259,7 @@ const SettingsMain = () => {
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
{intl.formatMessage(messages.trustProxy)}
|
{intl.formatMessage(messages.trustProxy)}
|
||||||
</span>
|
</span>
|
||||||
<Badge badgeType="primary">
|
<SettingsBadge badgeType="restartRequired" />
|
||||||
{intl.formatMessage(globalMessages.restartRequired)}
|
|
||||||
</Badge>
|
|
||||||
<span className="label-tip">
|
<span className="label-tip">
|
||||||
{intl.formatMessage(messages.trustProxyTip)}
|
{intl.formatMessage(messages.trustProxyTip)}
|
||||||
</span>
|
</span>
|
||||||
@@ -281,28 +280,30 @@ const SettingsMain = () => {
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
{intl.formatMessage(messages.csrfProtection)}
|
{intl.formatMessage(messages.csrfProtection)}
|
||||||
</span>
|
</span>
|
||||||
<Badge badgeType="danger" className="mr-2">
|
<SettingsBadge badgeType="advanced" className="mr-2" />
|
||||||
{intl.formatMessage(globalMessages.advanced)}
|
<SettingsBadge badgeType="restartRequired" />
|
||||||
</Badge>
|
|
||||||
<Badge badgeType="primary">
|
|
||||||
{intl.formatMessage(globalMessages.restartRequired)}
|
|
||||||
</Badge>
|
|
||||||
<span className="label-tip">
|
<span className="label-tip">
|
||||||
{intl.formatMessage(messages.csrfProtectionTip)}
|
{intl.formatMessage(messages.csrfProtectionTip)}
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<div className="form-input-area">
|
<div className="form-input-area">
|
||||||
<Field
|
<Tooltip
|
||||||
type="checkbox"
|
content={intl.formatMessage(
|
||||||
id="csrfProtection"
|
|
||||||
name="csrfProtection"
|
|
||||||
title={intl.formatMessage(
|
|
||||||
messages.csrfProtectionHoverTip
|
messages.csrfProtectionHoverTip
|
||||||
)}
|
)}
|
||||||
onChange={() => {
|
>
|
||||||
setFieldValue('csrfProtection', !values.csrfProtection);
|
<Field
|
||||||
}}
|
type="checkbox"
|
||||||
/>
|
id="csrfProtection"
|
||||||
|
name="csrfProtection"
|
||||||
|
onChange={() => {
|
||||||
|
setFieldValue(
|
||||||
|
'csrfProtection',
|
||||||
|
!values.csrfProtection
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="form-row">
|
<div className="form-row">
|
||||||
@@ -367,9 +368,7 @@ const SettingsMain = () => {
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
{intl.formatMessage(messages.hideAvailable)}
|
{intl.formatMessage(messages.hideAvailable)}
|
||||||
</span>
|
</span>
|
||||||
<Badge badgeType="warning">
|
<SettingsBadge badgeType="experimental" />
|
||||||
{intl.formatMessage(globalMessages.experimental)}
|
|
||||||
</Badge>
|
|
||||||
</label>
|
</label>
|
||||||
<div className="form-input-area">
|
<div className="form-input-area">
|
||||||
<Field
|
<Field
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
|||||||
import PageTitle from '@app/components/Common/PageTitle';
|
import PageTitle from '@app/components/Common/PageTitle';
|
||||||
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
||||||
import LibraryItem from '@app/components/Settings/LibraryItem';
|
import LibraryItem from '@app/components/Settings/LibraryItem';
|
||||||
|
import SettingsBadge from '@app/components/Settings/SettingsBadge';
|
||||||
import globalMessages from '@app/i18n/globalMessages';
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
import { SaveIcon } from '@heroicons/react/outline';
|
import { SaveIcon } from '@heroicons/react/outline';
|
||||||
import { RefreshIcon, SearchIcon, XIcon } from '@heroicons/react/solid';
|
import { RefreshIcon, SearchIcon, XIcon } from '@heroicons/react/solid';
|
||||||
@@ -567,9 +568,7 @@ const SettingsPlex = ({ onComplete }: SettingsPlexProps) => {
|
|||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
})}
|
})}
|
||||||
<Badge badgeType="danger" className="ml-2">
|
<SettingsBadge badgeType="advanced" className="ml-2" />
|
||||||
{intl.formatMessage(globalMessages.advanced)}
|
|
||||||
</Badge>
|
|
||||||
<span className="label-tip">
|
<span className="label-tip">
|
||||||
{intl.formatMessage(messages.webAppUrlTip)}
|
{intl.formatMessage(messages.webAppUrlTip)}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
|||||||
import PageTitle from '@app/components/Common/PageTitle';
|
import PageTitle from '@app/components/Common/PageTitle';
|
||||||
import type { PlayButtonLink } from '@app/components/Common/PlayButton';
|
import type { PlayButtonLink } from '@app/components/Common/PlayButton';
|
||||||
import PlayButton from '@app/components/Common/PlayButton';
|
import PlayButton from '@app/components/Common/PlayButton';
|
||||||
|
import Tooltip from '@app/components/Common/Tooltip';
|
||||||
import ExternalLinkBlock from '@app/components/ExternalLinkBlock';
|
import ExternalLinkBlock from '@app/components/ExternalLinkBlock';
|
||||||
import IssueModal from '@app/components/IssueModal';
|
import IssueModal from '@app/components/IssueModal';
|
||||||
import ManageSlideOver from '@app/components/ManageSlideOver';
|
import ManageSlideOver from '@app/components/ManageSlideOver';
|
||||||
@@ -68,6 +69,8 @@ const messages = defineMessages({
|
|||||||
streamingproviders: 'Currently Streaming On',
|
streamingproviders: 'Currently Streaming On',
|
||||||
productioncountries:
|
productioncountries:
|
||||||
'Production {countryCount, plural, one {Country} other {Countries}}',
|
'Production {countryCount, plural, one {Country} other {Countries}}',
|
||||||
|
reportissue: 'Report an Issue',
|
||||||
|
managemovie: 'Manage Movie',
|
||||||
});
|
});
|
||||||
|
|
||||||
interface TvDetailsProps {
|
interface TvDetailsProps {
|
||||||
@@ -389,38 +392,42 @@ const TvDetails = ({ tv }: TvDetailsProps) => {
|
|||||||
type: 'or',
|
type: 'or',
|
||||||
}
|
}
|
||||||
) && (
|
) && (
|
||||||
<Button
|
<Tooltip content={intl.formatMessage(messages.reportissue)}>
|
||||||
buttonType="warning"
|
<Button
|
||||||
className="ml-2 first:ml-0"
|
buttonType="warning"
|
||||||
onClick={() => setShowIssueModal(true)}
|
onClick={() => setShowIssueModal(true)}
|
||||||
>
|
className="ml-2 first:ml-0"
|
||||||
<ExclamationIcon className="w-5" />
|
>
|
||||||
</Button>
|
<ExclamationIcon />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
{hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && (
|
{hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && (
|
||||||
<Button
|
<Tooltip content={intl.formatMessage(messages.managemovie)}>
|
||||||
buttonType="default"
|
<Button
|
||||||
className="relative ml-2 first:ml-0"
|
buttonType="default"
|
||||||
onClick={() => setShowManager(true)}
|
onClick={() => setShowManager(true)}
|
||||||
>
|
className="relative ml-2 first:ml-0"
|
||||||
<CogIcon className="!mr-0" />
|
>
|
||||||
{hasPermission(
|
<CogIcon className="!mr-0" />
|
||||||
[Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],
|
{hasPermission(
|
||||||
{
|
[Permission.MANAGE_ISSUES, Permission.VIEW_ISSUES],
|
||||||
type: 'or',
|
{
|
||||||
}
|
type: 'or',
|
||||||
) &&
|
}
|
||||||
(
|
) &&
|
||||||
data.mediaInfo?.issues.filter(
|
(
|
||||||
(issue) => issue.status === IssueStatus.OPEN
|
data.mediaInfo?.issues.filter(
|
||||||
) ?? []
|
(issue) => issue.status === IssueStatus.OPEN
|
||||||
).length > 0 && (
|
) ?? []
|
||||||
<>
|
).length > 0 && (
|
||||||
<div className="absolute -right-1 -top-1 h-3 w-3 rounded-full bg-red-600" />
|
<>
|
||||||
<div className="absolute -right-1 -top-1 h-3 w-3 animate-ping rounded-full bg-red-600" />
|
<div className="absolute -right-1 -top-1 h-3 w-3 rounded-full bg-red-600" />
|
||||||
</>
|
<div className="absolute -right-1 -top-1 h-3 w-3 animate-ping rounded-full bg-red-600" />
|
||||||
)}
|
</>
|
||||||
</Button>
|
)}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import Badge from '@app/components/Common/Badge';
|
|
||||||
import Button from '@app/components/Common/Button';
|
import Button from '@app/components/Common/Button';
|
||||||
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
import LoadingSpinner from '@app/components/Common/LoadingSpinner';
|
||||||
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
import SensitiveInput from '@app/components/Common/SensitiveInput';
|
||||||
@@ -6,6 +5,7 @@ import NotificationTypeSelector, {
|
|||||||
ALL_NOTIFICATIONS,
|
ALL_NOTIFICATIONS,
|
||||||
} from '@app/components/NotificationTypeSelector';
|
} from '@app/components/NotificationTypeSelector';
|
||||||
import { OpenPgpLink } from '@app/components/Settings/Notifications/NotificationsEmail';
|
import { OpenPgpLink } from '@app/components/Settings/Notifications/NotificationsEmail';
|
||||||
|
import SettingsBadge from '@app/components/Settings/SettingsBadge';
|
||||||
import { useUser } from '@app/hooks/useUser';
|
import { useUser } from '@app/hooks/useUser';
|
||||||
import globalMessages from '@app/i18n/globalMessages';
|
import globalMessages from '@app/i18n/globalMessages';
|
||||||
import { SaveIcon } from '@heroicons/react/outline';
|
import { SaveIcon } from '@heroicons/react/outline';
|
||||||
@@ -105,9 +105,7 @@ const UserEmailSettings = () => {
|
|||||||
<span className="mr-2">
|
<span className="mr-2">
|
||||||
{intl.formatMessage(messages.pgpPublicKey)}
|
{intl.formatMessage(messages.pgpPublicKey)}
|
||||||
</span>
|
</span>
|
||||||
<Badge badgeType="danger">
|
<SettingsBadge badgeType="advanced" />
|
||||||
{intl.formatMessage(globalMessages.advanced)}
|
|
||||||
</Badge>
|
|
||||||
<span className="label-tip">
|
<span className="label-tip">
|
||||||
{intl.formatMessage(messages.pgpPublicKeyTip, {
|
{intl.formatMessage(messages.pgpPublicKeyTip, {
|
||||||
OpenPgpLink: OpenPgpLink,
|
OpenPgpLink: OpenPgpLink,
|
||||||
|
|||||||
@@ -160,6 +160,7 @@
|
|||||||
"components.MovieDetails.budget": "Budget",
|
"components.MovieDetails.budget": "Budget",
|
||||||
"components.MovieDetails.cast": "Cast",
|
"components.MovieDetails.cast": "Cast",
|
||||||
"components.MovieDetails.digitalrelease": "Digital Release",
|
"components.MovieDetails.digitalrelease": "Digital Release",
|
||||||
|
"components.MovieDetails.managemovie": "Manage Movie",
|
||||||
"components.MovieDetails.mark4kavailable": "Mark as Available in 4K",
|
"components.MovieDetails.mark4kavailable": "Mark as Available in 4K",
|
||||||
"components.MovieDetails.markavailable": "Mark as Available",
|
"components.MovieDetails.markavailable": "Mark as Available",
|
||||||
"components.MovieDetails.originallanguage": "Original Language",
|
"components.MovieDetails.originallanguage": "Original Language",
|
||||||
@@ -172,6 +173,7 @@
|
|||||||
"components.MovieDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}",
|
"components.MovieDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}",
|
||||||
"components.MovieDetails.recommendations": "Recommendations",
|
"components.MovieDetails.recommendations": "Recommendations",
|
||||||
"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.revenue": "Revenue",
|
"components.MovieDetails.revenue": "Revenue",
|
||||||
"components.MovieDetails.runtime": "{minutes} minutes",
|
"components.MovieDetails.runtime": "{minutes} minutes",
|
||||||
"components.MovieDetails.showless": "Show Less",
|
"components.MovieDetails.showless": "Show Less",
|
||||||
@@ -651,6 +653,7 @@
|
|||||||
"components.Settings.SettingsLogs.resumeLogs": "Resume",
|
"components.Settings.SettingsLogs.resumeLogs": "Resume",
|
||||||
"components.Settings.SettingsLogs.showall": "Show All Logs",
|
"components.Settings.SettingsLogs.showall": "Show All Logs",
|
||||||
"components.Settings.SettingsLogs.time": "Timestamp",
|
"components.Settings.SettingsLogs.time": "Timestamp",
|
||||||
|
"components.Settings.SettingsLogs.viewdetails": "View Details",
|
||||||
"components.Settings.SettingsUsers.defaultPermissions": "Default Permissions",
|
"components.Settings.SettingsUsers.defaultPermissions": "Default Permissions",
|
||||||
"components.Settings.SettingsUsers.defaultPermissionsTip": "Initial permissions assigned to new users",
|
"components.Settings.SettingsUsers.defaultPermissionsTip": "Initial permissions assigned to new users",
|
||||||
"components.Settings.SettingsUsers.localLogin": "Enable Local Sign-In",
|
"components.Settings.SettingsUsers.localLogin": "Enable Local Sign-In",
|
||||||
@@ -720,6 +723,7 @@
|
|||||||
"components.Settings.addradarr": "Add Radarr Server",
|
"components.Settings.addradarr": "Add Radarr Server",
|
||||||
"components.Settings.address": "Address",
|
"components.Settings.address": "Address",
|
||||||
"components.Settings.addsonarr": "Add Sonarr Server",
|
"components.Settings.addsonarr": "Add Sonarr Server",
|
||||||
|
"components.Settings.advancedTooltip": "Incorrectly configuring this setting may result in broken functionality",
|
||||||
"components.Settings.apikey": "API Key",
|
"components.Settings.apikey": "API Key",
|
||||||
"components.Settings.applicationTitle": "Application Title",
|
"components.Settings.applicationTitle": "Application Title",
|
||||||
"components.Settings.applicationurl": "Application URL",
|
"components.Settings.applicationurl": "Application URL",
|
||||||
@@ -737,6 +741,7 @@
|
|||||||
"components.Settings.deleteserverconfirm": "Are you sure you want to delete this server?",
|
"components.Settings.deleteserverconfirm": "Are you sure you want to delete this server?",
|
||||||
"components.Settings.email": "Email",
|
"components.Settings.email": "Email",
|
||||||
"components.Settings.enablessl": "Use SSL",
|
"components.Settings.enablessl": "Use SSL",
|
||||||
|
"components.Settings.experimentalTooltip": "Enabling this setting may result in unexpected application behavior",
|
||||||
"components.Settings.externalUrl": "External URL",
|
"components.Settings.externalUrl": "External URL",
|
||||||
"components.Settings.general": "General",
|
"components.Settings.general": "General",
|
||||||
"components.Settings.generalsettings": "General Settings",
|
"components.Settings.generalsettings": "General Settings",
|
||||||
@@ -777,6 +782,7 @@
|
|||||||
"components.Settings.radarrsettings": "Radarr Settings",
|
"components.Settings.radarrsettings": "Radarr Settings",
|
||||||
"components.Settings.region": "Discover Region",
|
"components.Settings.region": "Discover Region",
|
||||||
"components.Settings.regionTip": "Filter content by regional availability",
|
"components.Settings.regionTip": "Filter content by regional availability",
|
||||||
|
"components.Settings.restartrequiredTooltip": "Overseerr must be restarted for changes to this setting to take effect",
|
||||||
"components.Settings.scan": "Sync Libraries",
|
"components.Settings.scan": "Sync Libraries",
|
||||||
"components.Settings.scanning": "Syncing…",
|
"components.Settings.scanning": "Syncing…",
|
||||||
"components.Settings.serverLocal": "local",
|
"components.Settings.serverLocal": "local",
|
||||||
@@ -853,6 +859,7 @@
|
|||||||
"components.TvDetails.episodeRuntime": "Episode Runtime",
|
"components.TvDetails.episodeRuntime": "Episode Runtime",
|
||||||
"components.TvDetails.episodeRuntimeMinutes": "{runtime} minutes",
|
"components.TvDetails.episodeRuntimeMinutes": "{runtime} minutes",
|
||||||
"components.TvDetails.firstAirDate": "First Air Date",
|
"components.TvDetails.firstAirDate": "First Air Date",
|
||||||
|
"components.TvDetails.managemovie": "Manage Movie",
|
||||||
"components.TvDetails.network": "{networkCount, plural, one {Network} other {Networks}}",
|
"components.TvDetails.network": "{networkCount, plural, one {Network} other {Networks}}",
|
||||||
"components.TvDetails.nextAirDate": "Next Air Date",
|
"components.TvDetails.nextAirDate": "Next Air Date",
|
||||||
"components.TvDetails.originallanguage": "Original Language",
|
"components.TvDetails.originallanguage": "Original Language",
|
||||||
@@ -863,6 +870,7 @@
|
|||||||
"components.TvDetails.playonplex": "Play on Plex",
|
"components.TvDetails.playonplex": "Play on Plex",
|
||||||
"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.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}",
|
"components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}",
|
||||||
"components.TvDetails.showtype": "Series Type",
|
"components.TvDetails.showtype": "Series Type",
|
||||||
"components.TvDetails.similar": "Similar Series",
|
"components.TvDetails.similar": "Similar Series",
|
||||||
|
|||||||
Reference in New Issue
Block a user