refactor(ui): improved alerts for services settings & removed alert titles (#1280)

* refactor(ui): improved alerts for services settings & removed alert titles

* fix(ui): set styling of alert links to be consistent w/ others

* fix(ui): clarify appropriate 4K setting when user has not configured a default non-4K server

* fix: remove unused var/eslint-disable & correct string
This commit is contained in:
TheCatLady
2021-04-13 22:20:25 -04:00
committed by GitHub
parent ad67381397
commit 2cd952d1ca
18 changed files with 174 additions and 184 deletions

View File

@@ -30,7 +30,6 @@ const messages = defineMessages({
'SSL should be disabled on standard TLS connections (port 587)',
senderName: 'Sender Name',
validationEmail: 'You must provide a valid email address',
emailNotificationTypesAlert: 'Email Notification Recipients',
emailNotificationTypesAlertDescription:
'<strong>Media Requested</strong>, <strong>Media Automatically Approved</strong>, and <strong>Media Failed</strong> email notifications are sent to all users with the <strong>Manage Requests</strong> permission.',
emailNotificationTypesAlertDescriptionPt2:
@@ -198,38 +197,40 @@ const NotificationsEmail: React.FC = () => {
return (
<>
<Alert
title={intl.formatMessage(messages.emailNotificationTypesAlert)}
title={
<>
<p className="mb-2">
{intl.formatMessage(
messages.emailNotificationTypesAlertDescription,
{
strong: function strong(msg) {
return (
<strong className="font-semibold text-indigo-100">
{msg}
</strong>
);
},
}
)}
</p>
<p>
{intl.formatMessage(
messages.emailNotificationTypesAlertDescriptionPt2,
{
strong: function strong(msg) {
return (
<strong className="font-semibold text-indigo-100">
{msg}
</strong>
);
},
}
)}
</p>
</>
}
type="info"
>
<p className="mb-2">
{intl.formatMessage(
messages.emailNotificationTypesAlertDescription,
{
strong: function strong(msg) {
return (
<strong className="font-normal text-indigo-100">
{msg}
</strong>
);
},
}
)}
</p>
<p>
{intl.formatMessage(
messages.emailNotificationTypesAlertDescriptionPt2,
{
strong: function strong(msg) {
return (
<strong className="font-normal text-indigo-100">
{msg}
</strong>
);
},
}
)}
</p>
</Alert>
/>
<Form className="section">
<div className="form-row">
<label htmlFor="enabled" className="checkbox-label">

View File

@@ -19,7 +19,6 @@ const messages = defineMessages({
'Pushbullet notification settings saved successfully!',
pushbulletSettingsFailed: 'Pushbullet notification settings failed to save.',
testSent: 'Pushbullet test notification sent!',
settingUpPushbullet: 'Setting Up Pushbullet Notifications',
settingUpPushbulletDescription:
'To configure Pushbullet notifications, you will need to <CreateAccessTokenLink>create an access token</CreateAccessTokenLink>.',
});
@@ -95,24 +94,25 @@ const NotificationsPushbullet: React.FC = () => {
return (
<>
<Alert
title={intl.formatMessage(messages.settingUpPushbullet)}
title={intl.formatMessage(
messages.settingUpPushbulletDescription,
{
CreateAccessTokenLink: function CreateAccessTokenLink(msg) {
return (
<a
href="https://www.pushbullet.com/#settings"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
{msg}
</a>
);
},
}
)}
type="info"
>
{intl.formatMessage(messages.settingUpPushbulletDescription, {
CreateAccessTokenLink: function CreateAccessTokenLink(msg) {
return (
<a
href="https://www.pushbullet.com/#settings"
className="text-indigo-100 hover:text-white hover:underline"
target="_blank"
rel="noreferrer"
>
{msg}
</a>
);
},
})}
</Alert>
/>
<Form className="section">
<div className="form-row">
<label htmlFor="enabled" className="checkbox-label">

View File

@@ -20,7 +20,6 @@ const messages = defineMessages({
pushoversettingssaved: 'Pushover notification settings saved successfully!',
pushoversettingsfailed: 'Pushover notification settings failed to save.',
testsent: 'Pushover test notification sent!',
settinguppushover: 'Setting Up Pushover Notifications',
settinguppushoverDescription:
'To configure Pushover notifications, you will need to <RegisterApplicationLink>register an application</RegisterApplicationLink> and enter the API token below. (You can use one of the <IconLink>official Overseerr icons on GitHub</IconLink>.)',
});
@@ -116,15 +115,12 @@ const NotificationsPushover: React.FC = () => {
return (
<>
<Alert
title={intl.formatMessage(messages.settinguppushover)}
type="info"
>
{intl.formatMessage(messages.settinguppushoverDescription, {
title={intl.formatMessage(messages.settinguppushoverDescription, {
RegisterApplicationLink: function RegisterApplicationLink(msg) {
return (
<a
href="https://pushover.net/apps/build"
className="text-indigo-100 hover:text-white hover:underline"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
@@ -136,7 +132,7 @@ const NotificationsPushover: React.FC = () => {
return (
<a
href="https://github.com/sct/overseerr/tree/develop/public"
className="text-indigo-100 hover:text-white hover:underline"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
@@ -145,7 +141,8 @@ const NotificationsPushover: React.FC = () => {
);
},
})}
</Alert>
type="info"
/>
<Form className="section">
<div className="form-row">
<label htmlFor="enabled" className="checkbox-label">

View File

@@ -17,7 +17,6 @@ const messages = defineMessages({
slacksettingssaved: 'Slack notification settings saved successfully!',
slacksettingsfailed: 'Slack notification settings failed to save.',
testsent: 'Slack test notification sent!',
settingupslack: 'Setting Up Slack Notifications',
settingupslackDescription:
'To configure Slack notifications, you will need to create an <WebhookLink>Incoming Webhook</WebhookLink> integration and enter the webhook URL below.',
validationWebhookUrl: 'You must provide a valid URL',
@@ -48,13 +47,13 @@ const NotificationsSlack: React.FC = () => {
return (
<>
<Alert title={intl.formatMessage(messages.settingupslack)} type="info">
{intl.formatMessage(messages.settingupslackDescription, {
<Alert
title={intl.formatMessage(messages.settingupslackDescription, {
WebhookLink: function WebhookLink(msg) {
return (
<a
href="https://my.slack.com/services/new/incoming-webhook/"
className="text-indigo-100 hover:text-white hover:underline"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
@@ -63,7 +62,8 @@ const NotificationsSlack: React.FC = () => {
);
},
})}
</Alert>
type="info"
/>
<Formik
initialValues={{
enabled: data.enabled,

View File

@@ -23,7 +23,6 @@ const messages = defineMessages({
telegramsettingssaved: 'Telegram notification settings saved successfully!',
telegramsettingsfailed: 'Telegram notification settings failed to save.',
testsent: 'Telegram test notification sent!',
settinguptelegram: 'Setting Up Telegram Notifications',
settinguptelegramDescription:
'To configure Telegram notifications, you will need to <CreateBotLink>create a bot</CreateBotLink> and get the bot API key. Additionally, you will need the chat ID for the chat to which you would like to send notifications. You can find this by adding <GetIdBotLink>@get_id_bot</GetIdBotLink> to the chat and issuing the <code>/my_id</code> command.',
sendSilently: 'Send Silently',
@@ -123,15 +122,12 @@ const NotificationsTelegram: React.FC = () => {
return (
<>
<Alert
title={intl.formatMessage(messages.settinguptelegram)}
type="info"
>
{intl.formatMessage(messages.settinguptelegramDescription, {
title={intl.formatMessage(messages.settinguptelegramDescription, {
CreateBotLink: function CreateBotLink(msg) {
return (
<a
href="https://core.telegram.org/bots#6-botfather"
className="text-indigo-100 hover:text-white hover:underline"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
@@ -143,7 +139,7 @@ const NotificationsTelegram: React.FC = () => {
return (
<a
href="https://telegram.me/get_id_bot"
className="text-indigo-100 hover:text-white hover:underline"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
@@ -155,7 +151,8 @@ const NotificationsTelegram: React.FC = () => {
return <code className="bg-opacity-50">{msg}</code>;
},
})}
</Alert>
type="info"
/>
<Form className="section">
<div className="form-row">
<label htmlFor="enabled" className="checkbox-label">

View File

@@ -70,7 +70,7 @@ const NotificationsWebhook: React.FC = () => {
otherwise: Yup.string().nullable(),
})
.matches(
// eslint-disable-next-line
// eslint-disable-next-line no-useless-escape
/^(https?:)?\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*)?([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i,
intl.formatMessage(messages.validationWebhookUrl)
),

View File

@@ -18,7 +18,6 @@ const messages = defineMessages({
latestversion: 'Latest',
currentversion: 'Current Version',
viewchangelog: 'View Changelog',
runningDevelop: 'Development Version',
runningDevelopMessage:
'The latest changes to the <code>develop</code> branch of Overseerr are not shown below. Please see the commit history for this branch on <GithubLink>GitHub</GithubLink> for details.',
});
@@ -159,8 +158,8 @@ const Releases: React.FC<ReleasesProps> = ({ currentVersion }) => {
<h3 className="heading">{intl.formatMessage(messages.releases)}</h3>
<div className="section">
{currentVersion.startsWith('develop-') && (
<Alert title={intl.formatMessage(messages.runningDevelop)}>
{intl.formatMessage(messages.runningDevelopMessage, {
<Alert
title={intl.formatMessage(messages.runningDevelopMessage, {
code: function code(msg) {
return <code className="bg-opacity-50">{msg}</code>;
},
@@ -177,7 +176,7 @@ const Releases: React.FC<ReleasesProps> = ({ currentVersion }) => {
);
},
})}
</Alert>
/>
)}
{data?.map((release, index) => {
return (

View File

@@ -38,9 +38,8 @@ const messages = defineMessages({
toastPlexConnecting: 'Attempting to connect to Plex…',
toastPlexConnectingSuccess: 'Plex connection established successfully!',
toastPlexConnectingFailure: 'Failed to connect to Plex.',
settingUpPlex: 'Setting Up Plex',
settingUpPlexDescription:
'To set up Plex, you can either enter your details manually or select a server retrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Press the button to the right of the dropdown to check connectivity and retrieve available servers.',
'To set up Plex, you can either enter your details manually or select a server retrieved from <RegisterPlexTVLink>plex.tv</RegisterPlexTVLink>. Press the button to the right of the dropdown to fetch the list of available servers.',
hostname: 'Hostname or IP Address',
port: 'Port',
enablessl: 'Enable SSL',
@@ -81,7 +80,6 @@ interface PresetServerDisplay {
ssl: boolean;
uri: string;
address: string;
host?: string;
port: number;
local: boolean;
status?: boolean;
@@ -94,7 +92,6 @@ interface SettingsPlexProps {
const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
const [isSyncing, setIsSyncing] = useState(false);
const [isRefreshingPresets, setIsRefreshingPresets] = useState(false);
const [submitError, setSubmitError] = useState<string | null>(null);
const [availableServers, setAvailableServers] = useState<PlexDevice[] | null>(
null
);
@@ -268,13 +265,13 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
{intl.formatMessage(messages.plexsettingsDescription)}
</p>
<div className="section">
<Alert title={intl.formatMessage(messages.settingUpPlex)} type="info">
{intl.formatMessage(messages.settingUpPlexDescription, {
<Alert
title={intl.formatMessage(messages.settingUpPlexDescription, {
RegisterPlexTVLink: function RegisterPlexTVLink(msg) {
return (
<a
href="https://plex.tv"
className="text-indigo-100 hover:text-white hover:underline"
className="text-white transition duration-300 hover:underline"
target="_blank"
rel="noreferrer"
>
@@ -283,7 +280,8 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
);
},
})}
</Alert>
type="info"
/>
</div>
</div>
<Formik
@@ -314,7 +312,6 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
} as PlexSettings);
revalidate();
setSubmitError(null);
if (toastId) {
removeToast(toastId);
}
@@ -333,7 +330,6 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
autoDismiss: true,
appearance: 'error',
});
setSubmitError(e.response.data.message);
}
}}
>
@@ -513,18 +509,6 @@ const SettingsPlex: React.FC<SettingsPlexProps> = ({ onComplete }) => {
/>
</div>
</div>
{submitError && (
<div className="mt-6 sm:gap-4 sm:items-start">
<Alert
title={intl.formatMessage(
messages.toastPlexConnectingFailure
)}
type="error"
>
{submitError}
</Alert>
</div>
)}
<div className="actions">
<div className="flex justify-end">
<span className="inline-flex ml-3 rounded-md shadow-sm">

View File

@@ -20,11 +20,9 @@ import SonarrModal from './SonarrModal';
const messages = defineMessages({
services: 'Services',
radarrsettings: 'Radarr Settings',
radarrSettingsDescription:
'Configure your Radarr connection below. You can have multiple Radarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.',
sonarrsettings: 'Sonarr Settings',
sonarrSettingsDescription:
'Configure your Sonarr connection below. You can have multiple Sonarr configurations, but only two can be active as defaults at any time (one for standard HD and one for 4K). Administrators can override the server which is used for new requests.',
serviceSettingsDescription:
'Configure your {serverType} server(s) below. You can connect multiple {serverType} servers, but only two of them can be marked as defaults (one non-4K and one 4K). Administrators are able to override the server used to process new requests prior to approval.',
deleteserverconfirm: 'Are you sure you want to delete this server?',
ssl: 'SSL',
default: 'Default',
@@ -33,9 +31,12 @@ const messages = defineMessages({
activeProfile: 'Active Profile',
addradarr: 'Add Radarr Server',
addsonarr: 'Add Sonarr Server',
nodefault: 'No Default Server',
nodefaultdescription:
'At least one server must be marked as default before any requests will make it to your services.',
noDefaultServer:
'At least one {serverType} server must be marked as default in order for {mediaType} requests to be processed.',
noDefaultNon4kServer:
'If you only have a single {serverType} server for both non-4K and 4K content (or if you only download 4K content), your {serverType} server should <strong>NOT</strong> be designated as a 4K server.',
mediaTypeMovie: 'movie',
mediaTypeSeries: 'series',
});
interface ServerInstanceProps {
@@ -229,7 +230,9 @@ const SettingsServices: React.FC = () => {
{intl.formatMessage(messages.radarrsettings)}
</h3>
<p className="description">
{intl.formatMessage(messages.radarrSettingsDescription)}
{intl.formatMessage(messages.serviceSettingsDescription, {
serverType: 'Radarr',
})}
</p>
</div>
{editRadarrModal.open && (
@@ -284,13 +287,31 @@ const SettingsServices: React.FC = () => {
{radarrData && !radarrError && (
<>
{radarrData.length > 0 &&
!radarrData.some(
(radarr) => radarr.isDefault && !radarr.is4k
) && (
<Alert title={intl.formatMessage(messages.nodefault)}>
<p>{intl.formatMessage(messages.nodefaultdescription)}</p>
</Alert>
)}
(!radarrData.some((radarr) => radarr.isDefault) ? (
<Alert
title={intl.formatMessage(messages.noDefaultServer, {
serverType: 'Radarr',
mediaType: intl.formatMessage(messages.mediaTypeMovie),
})}
/>
) : (
!radarrData.some(
(radarr) => radarr.isDefault && !radarr.is4k
) && (
<Alert
title={intl.formatMessage(messages.noDefaultNon4kServer, {
serverType: 'Radarr',
strong: function strong(msg) {
return (
<strong className="font-semibold text-yellow-100">
{msg}
</strong>
);
},
})}
/>
)
))}
<ul className="grid max-w-6xl grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3">
{radarrData.map((radarr) => (
<ServerInstance
@@ -347,7 +368,9 @@ const SettingsServices: React.FC = () => {
{intl.formatMessage(messages.sonarrsettings)}
</h3>
<p className="description">
{intl.formatMessage(messages.sonarrSettingsDescription)}
{intl.formatMessage(messages.serviceSettingsDescription, {
serverType: 'Sonarr',
})}
</p>
</div>
<div className="section">
@@ -355,13 +378,31 @@ const SettingsServices: React.FC = () => {
{sonarrData && !sonarrError && (
<>
{sonarrData.length > 0 &&
!sonarrData.some(
(sonarr) => sonarr.isDefault && !sonarr.is4k
) && (
<Alert title={intl.formatMessage(messages.nodefault)}>
<p>{intl.formatMessage(messages.nodefaultdescription)}</p>
</Alert>
)}
(!sonarrData.some((sonarr) => sonarr.isDefault) ? (
<Alert
title={intl.formatMessage(messages.noDefaultServer, {
serverType: 'Sonarr',
mediaType: intl.formatMessage(messages.mediaTypeSeries),
})}
/>
) : (
!sonarrData.some(
(sonarr) => sonarr.isDefault && !sonarr.is4k
) && (
<Alert
title={intl.formatMessage(messages.noDefaultNon4kServer, {
serverType: 'Sonarr',
strong: function strong(msg) {
return (
<strong className="font-semibold text-yellow-100">
{msg}
</strong>
);
},
})}
/>
)
))}
<ul className="grid max-w-6xl grid-cols-1 gap-6 lg:grid-cols-2 xl:grid-cols-3">
{sonarrData.map((sonarr) => (
<ServerInstance