diff --git a/src/components/Common/Tooltip/index.tsx b/src/components/Common/Tooltip/index.tsx index 3eeffd4b..b0c4fb2e 100644 --- a/src/components/Common/Tooltip/index.tsx +++ b/src/components/Common/Tooltip/index.tsx @@ -1,29 +1,31 @@ +import React from 'react'; import type { Config } from 'react-popper-tooltip'; import { usePopperTooltip } from 'react-popper-tooltip'; type TooltipProps = { content: React.ReactNode; - children: React.ReactNode; - tooltipConfig?: Config; + children: React.ReactElement; + tooltipConfig?: Partial; }; const Tooltip = ({ children, content, tooltipConfig }: TooltipProps) => { const { getTooltipProps, setTooltipRef, setTriggerRef, visible } = usePopperTooltip({ followCursor: true, - placement: 'left-end', + offset: [-28, 6], + placement: 'auto-end', ...tooltipConfig, }); return ( <> -
{children}
+ {React.cloneElement(children, { ref: setTriggerRef })} {visible && (
{content} diff --git a/src/components/MovieDetails/index.tsx b/src/components/MovieDetails/index.tsx index 6c89f9d3..95ac1ae1 100644 --- a/src/components/MovieDetails/index.tsx +++ b/src/components/MovieDetails/index.tsx @@ -78,6 +78,8 @@ const messages = defineMessages({ theatricalrelease: 'Theatrical Release', digitalrelease: 'Digital Release', physicalrelease: 'Physical Release', + reportissue: 'Report an Issue', + managemovie: 'Manage Movie', }); interface MovieDetailsProps { @@ -388,38 +390,42 @@ const MovieDetails = ({ movie }: MovieDetailsProps) => { type: 'or', } ) && ( + + + + )} + {hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && ( + - )} - {hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && ( - + )}
diff --git a/src/components/Settings/Notifications/NotificationsEmail.tsx b/src/components/Settings/Notifications/NotificationsEmail.tsx index 9222c996..242c0b85 100644 --- a/src/components/Settings/Notifications/NotificationsEmail.tsx +++ b/src/components/Settings/Notifications/NotificationsEmail.tsx @@ -1,7 +1,7 @@ -import Badge from '@app/components/Common/Badge'; import Button from '@app/components/Common/Button'; import LoadingSpinner from '@app/components/Common/LoadingSpinner'; import SensitiveInput from '@app/components/Common/SensitiveInput'; +import SettingsBadge from '@app/components/Settings/SettingsBadge'; import globalMessages from '@app/i18n/globalMessages'; import { BeakerIcon, SaveIcon } from '@heroicons/react/outline'; import axios from 'axios'; @@ -382,9 +382,7 @@ const NotificationsEmail = () => { {intl.formatMessage(messages.pgpPrivateKey)} - - {intl.formatMessage(globalMessages.advanced)} - + {intl.formatMessage(messages.pgpPrivateKeyTip, { OpenPgpLink: OpenPgpLink, @@ -414,9 +412,7 @@ const NotificationsEmail = () => { {intl.formatMessage(messages.pgpPassword)} - - {intl.formatMessage(globalMessages.advanced)} - + {intl.formatMessage(messages.pgpPasswordTip, { OpenPgpLink: OpenPgpLink, diff --git a/src/components/Settings/SettingsBadge.tsx b/src/components/Settings/SettingsBadge.tsx new file mode 100644 index 00000000..c4f12ef3 --- /dev/null +++ b/src/components/Settings/SettingsBadge.tsx @@ -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 ( + + + {intl.formatMessage(globalMessages.advanced)} + + + ); + case 'experimental': + return ( + + + {intl.formatMessage(globalMessages.experimental)} + + + ); + case 'restartRequired': + return ( + + + {intl.formatMessage(globalMessages.restartRequired)} + + + ); + default: + return null; + } +}; + +export default SettingsBadge; diff --git a/src/components/Settings/SettingsLogs/index.tsx b/src/components/Settings/SettingsLogs/index.tsx index 1959fa25..ac677dcf 100644 --- a/src/components/Settings/SettingsLogs/index.tsx +++ b/src/components/Settings/SettingsLogs/index.tsx @@ -4,6 +4,7 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner'; import Modal from '@app/components/Common/Modal'; import PageTitle from '@app/components/Common/PageTitle'; import Table from '@app/components/Common/Table'; +import Tooltip from '@app/components/Common/Tooltip'; import Transition from '@app/components/Transition'; import { useUpdateQueryParams } from '@app/hooks/useUpdateQueryParams'; import globalMessages from '@app/i18n/globalMessages'; @@ -47,6 +48,7 @@ const messages = defineMessages({ logDetails: 'Log Details', extraData: 'Additional Data', copiedLogMessage: 'Copied log message to clipboard.', + viewdetails: 'View Details', }); type Filter = 'debug' | 'info' | 'warn' | 'error'; @@ -327,23 +329,31 @@ const SettingsLogs = () => { {row.message} {row.data && ( + + + + )} + - )} - + ); diff --git a/src/components/Settings/SettingsMain.tsx b/src/components/Settings/SettingsMain.tsx index 96c7765a..f33ad752 100644 --- a/src/components/Settings/SettingsMain.tsx +++ b/src/components/Settings/SettingsMain.tsx @@ -1,11 +1,12 @@ -import Badge from '@app/components/Common/Badge'; import Button from '@app/components/Common/Button'; import LoadingSpinner from '@app/components/Common/LoadingSpinner'; import PageTitle from '@app/components/Common/PageTitle'; import SensitiveInput from '@app/components/Common/SensitiveInput'; +import Tooltip from '@app/components/Common/Tooltip'; import LanguageSelector from '@app/components/LanguageSelector'; import RegionSelector from '@app/components/RegionSelector'; import CopyButton from '@app/components/Settings/CopyButton'; +import SettingsBadge from '@app/components/Settings/SettingsBadge'; import type { AvailableLocale } from '@app/context/LanguageContext'; import { availableLanguages } from '@app/context/LanguageContext'; import useLocale from '@app/hooks/useLocale'; @@ -258,9 +259,7 @@ const SettingsMain = () => { {intl.formatMessage(messages.trustProxy)} - - {intl.formatMessage(globalMessages.restartRequired)} - + {intl.formatMessage(messages.trustProxyTip)} @@ -281,28 +280,30 @@ const SettingsMain = () => { {intl.formatMessage(messages.csrfProtection)} - - {intl.formatMessage(globalMessages.advanced)} - - - {intl.formatMessage(globalMessages.restartRequired)} - + + {intl.formatMessage(messages.csrfProtectionTip)}
- { - setFieldValue('csrfProtection', !values.csrfProtection); - }} - /> + > + { + setFieldValue( + 'csrfProtection', + !values.csrfProtection + ); + }} + /> +
@@ -367,9 +368,7 @@ const SettingsMain = () => { {intl.formatMessage(messages.hideAvailable)} - - {intl.formatMessage(globalMessages.experimental)} - +
{ ), })} - - {intl.formatMessage(globalMessages.advanced)} - + {intl.formatMessage(messages.webAppUrlTip)} diff --git a/src/components/TvDetails/index.tsx b/src/components/TvDetails/index.tsx index 53d558f2..2f19ee23 100644 --- a/src/components/TvDetails/index.tsx +++ b/src/components/TvDetails/index.tsx @@ -9,6 +9,7 @@ import LoadingSpinner from '@app/components/Common/LoadingSpinner'; import PageTitle from '@app/components/Common/PageTitle'; import type { PlayButtonLink } 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 IssueModal from '@app/components/IssueModal'; import ManageSlideOver from '@app/components/ManageSlideOver'; @@ -68,6 +69,8 @@ const messages = defineMessages({ streamingproviders: 'Currently Streaming On', productioncountries: 'Production {countryCount, plural, one {Country} other {Countries}}', + reportissue: 'Report an Issue', + managemovie: 'Manage Movie', }); interface TvDetailsProps { @@ -389,38 +392,42 @@ const TvDetails = ({ tv }: TvDetailsProps) => { type: 'or', } ) && ( + + + + )} + {hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && ( + - )} - {hasPermission(Permission.MANAGE_REQUESTS) && data.mediaInfo && ( - + )}
diff --git a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsx b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsx index 167454ae..942ea707 100644 --- a/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsx +++ b/src/components/UserProfile/UserSettings/UserNotificationSettings/UserNotificationsEmail.tsx @@ -1,4 +1,3 @@ -import Badge from '@app/components/Common/Badge'; import Button from '@app/components/Common/Button'; import LoadingSpinner from '@app/components/Common/LoadingSpinner'; import SensitiveInput from '@app/components/Common/SensitiveInput'; @@ -6,6 +5,7 @@ import NotificationTypeSelector, { ALL_NOTIFICATIONS, } from '@app/components/NotificationTypeSelector'; import { OpenPgpLink } from '@app/components/Settings/Notifications/NotificationsEmail'; +import SettingsBadge from '@app/components/Settings/SettingsBadge'; import { useUser } from '@app/hooks/useUser'; import globalMessages from '@app/i18n/globalMessages'; import { SaveIcon } from '@heroicons/react/outline'; @@ -105,9 +105,7 @@ const UserEmailSettings = () => { {intl.formatMessage(messages.pgpPublicKey)} - - {intl.formatMessage(globalMessages.advanced)} - + {intl.formatMessage(messages.pgpPublicKeyTip, { OpenPgpLink: OpenPgpLink, diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 3a3d01ae..b9affda9 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -160,6 +160,7 @@ "components.MovieDetails.budget": "Budget", "components.MovieDetails.cast": "Cast", "components.MovieDetails.digitalrelease": "Digital Release", + "components.MovieDetails.managemovie": "Manage Movie", "components.MovieDetails.mark4kavailable": "Mark as Available in 4K", "components.MovieDetails.markavailable": "Mark as Available", "components.MovieDetails.originallanguage": "Original Language", @@ -172,6 +173,7 @@ "components.MovieDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}", "components.MovieDetails.recommendations": "Recommendations", "components.MovieDetails.releasedate": "{releaseCount, plural, one {Release Date} other {Release Dates}}", + "components.MovieDetails.reportissue": "Report an Issue", "components.MovieDetails.revenue": "Revenue", "components.MovieDetails.runtime": "{minutes} minutes", "components.MovieDetails.showless": "Show Less", @@ -651,6 +653,7 @@ "components.Settings.SettingsLogs.resumeLogs": "Resume", "components.Settings.SettingsLogs.showall": "Show All Logs", "components.Settings.SettingsLogs.time": "Timestamp", + "components.Settings.SettingsLogs.viewdetails": "View Details", "components.Settings.SettingsUsers.defaultPermissions": "Default Permissions", "components.Settings.SettingsUsers.defaultPermissionsTip": "Initial permissions assigned to new users", "components.Settings.SettingsUsers.localLogin": "Enable Local Sign-In", @@ -720,6 +723,7 @@ "components.Settings.addradarr": "Add Radarr Server", "components.Settings.address": "Address", "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.applicationTitle": "Application Title", "components.Settings.applicationurl": "Application URL", @@ -737,6 +741,7 @@ "components.Settings.deleteserverconfirm": "Are you sure you want to delete this server?", "components.Settings.email": "Email", "components.Settings.enablessl": "Use SSL", + "components.Settings.experimentalTooltip": "Enabling this setting may result in unexpected application behavior", "components.Settings.externalUrl": "External URL", "components.Settings.general": "General", "components.Settings.generalsettings": "General Settings", @@ -777,6 +782,7 @@ "components.Settings.radarrsettings": "Radarr Settings", "components.Settings.region": "Discover Region", "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.scanning": "Syncing…", "components.Settings.serverLocal": "local", @@ -853,6 +859,7 @@ "components.TvDetails.episodeRuntime": "Episode Runtime", "components.TvDetails.episodeRuntimeMinutes": "{runtime} minutes", "components.TvDetails.firstAirDate": "First Air Date", + "components.TvDetails.managemovie": "Manage Movie", "components.TvDetails.network": "{networkCount, plural, one {Network} other {Networks}}", "components.TvDetails.nextAirDate": "Next Air Date", "components.TvDetails.originallanguage": "Original Language", @@ -863,6 +870,7 @@ "components.TvDetails.playonplex": "Play on Plex", "components.TvDetails.productioncountries": "Production {countryCount, plural, one {Country} other {Countries}}", "components.TvDetails.recommendations": "Recommendations", + "components.TvDetails.reportissue": "Report an Issue", "components.TvDetails.seasons": "{seasonCount, plural, one {# Season} other {# Seasons}}", "components.TvDetails.showtype": "Series Type", "components.TvDetails.similar": "Similar Series",