+
+ {values.useSsl ? 'https://' : 'http://'}
+
{errors.hostname && touched.hostname && (
diff --git a/src/components/Settings/SettingsServices.tsx b/src/components/Settings/SettingsServices.tsx
index 07ccafd3a..5a3b1e8c5 100644
--- a/src/components/Settings/SettingsServices.tsx
+++ b/src/components/Settings/SettingsServices.tsx
@@ -1,5 +1,5 @@
import React, { useState } from 'react';
-import { defineMessages, FormattedMessage } from 'react-intl';
+import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import Badge from '../Common/Badge';
import Button from '../Common/Button';
import useSWR from 'swr';
@@ -31,8 +31,48 @@ const messages = defineMessages({
activeProfile: 'Active Profile',
addradarr: 'Add Radarr Server',
addsonarr: 'Add Sonarr Server',
+ nodefault: 'No default server selected!',
+ nodefaultdescription:
+ 'At least one server must be marked as default before any requests will make it to your services.',
+ no4kimplemented: '(Default 4K servers are not currently implemented)',
});
+const NoDefaultAlert: React.FC = () => {
+ const intl = useIntl();
+ return (
+
+
+
+
+
+ {intl.formatMessage(messages.nodefault)}
+
+
+
{intl.formatMessage(messages.nodefaultdescription)}
+
+ {intl.formatMessage(messages.no4kimplemented)}
+
+
+
+
+
+ );
+};
+
interface ServerInstanceProps {
name: string;
isDefault?: boolean;
@@ -249,51 +289,57 @@ const SettingsServices: React.FC = () => {
{!radarrData && !radarrError &&
}
{radarrData && !radarrError && (
-
- {radarrData.map((radarr) => (
- setEditRadarrModal({ open: true, radarr })}
- onDelete={() =>
- setDeleteServerModal({
- open: true,
- serverId: radarr.id,
- type: 'radarr',
- })
- }
- />
- ))}
-
-
-
- setEditRadarrModal({ open: true, radarr: null })
+ <>
+ {radarrData.length > 0 &&
+ !radarrData.some(
+ (radarr) => radarr.isDefault && !radarr.is4k
+ ) && }
+
+ {radarrData.map((radarr) => (
+ setEditRadarrModal({ open: true, radarr })}
+ onDelete={() =>
+ setDeleteServerModal({
+ open: true,
+ serverId: radarr.id,
+ type: 'radarr',
+ })
}
- >
-
+ ))}
+
+
+
+ setEditRadarrModal({ open: true, radarr: null })
+ }
>
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ >
)}
@@ -307,52 +353,58 @@ const SettingsServices: React.FC = () => {
{!sonarrData && !sonarrError &&
}
{sonarrData && !sonarrError && (
-
- {sonarrData.map((sonarr) => (
- setEditSonarrModal({ open: true, sonarr })}
- onDelete={() =>
- setDeleteServerModal({
- open: true,
- serverId: sonarr.id,
- type: 'sonarr',
- })
- }
- />
- ))}
-
-
-
- setEditSonarrModal({ open: true, sonarr: null })
+ <>
+ {sonarrData.length > 0 &&
+ !sonarrData.some(
+ (sonarr) => sonarr.isDefault && !sonarr.is4k
+ ) && }
+
+ {sonarrData.map((sonarr) => (
+ setEditSonarrModal({ open: true, sonarr })}
+ onDelete={() =>
+ setDeleteServerModal({
+ open: true,
+ serverId: sonarr.id,
+ type: 'sonarr',
+ })
}
- >
-
+ ))}
+
+
+
+ setEditSonarrModal({ open: true, sonarr: null })
+ }
>
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+ >
)}
>
diff --git a/src/components/Settings/SonarrModal/index.tsx b/src/components/Settings/SonarrModal/index.tsx
index a98c64ed0..ad6fee594 100644
--- a/src/components/Settings/SonarrModal/index.tsx
+++ b/src/components/Settings/SonarrModal/index.tsx
@@ -40,6 +40,10 @@ const messages = defineMessages({
server4k: '4K Server',
selectQualityProfile: 'Select a Quality Profile',
selectRootFolder: 'Select a Root Folder',
+ loadingprofiles: 'Loading quality profiles…',
+ testFirstQualityProfiles: 'Test your connection to load quality profiles',
+ loadingrootfolders: 'Loading root folders…',
+ testFirstRootFolders: 'Test your connection to load root folders',
});
interface TestResponse {
@@ -225,6 +229,7 @@ const SonarrModal: React.FC
= ({
handleSubmit,
setFieldValue,
isSubmitting,
+ isValid,
}) => {
return (
= ({
secondaryDisabled={
!values.apiKey || !values.hostname || !values.port || isTesting
}
- okDisabled={!isValidated || isSubmitting || isTesting}
+ okDisabled={!isValidated || isSubmitting || isTesting || !isValid}
onOk={() => handleSubmit()}
title={
!sonarr
@@ -319,6 +324,9 @@ const SonarrModal: React.FC = ({
+
+ {values.ssl ? 'https://' : 'http://'}
+
= ({
setIsValidated(false);
setFieldValue('hostname', e.target.value);
}}
- className="flex-1 form-input block w-full min-w-0 rounded-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
+ className="flex-1 form-input block w-full min-w-0 rounded-r-md transition duration-150 ease-in-out sm:text-sm sm:leading-5 bg-gray-700 border border-gray-500"
/>
{errors.hostname && touched.hostname && (
@@ -449,10 +457,17 @@ const SonarrModal: React.FC
= ({
as="select"
id="activeProfileId"
name="activeProfileId"
- className="mt-1 form-select rounded-md block w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5"
+ disabled={!isValidated || isTesting}
+ className="mt-1 form-select rounded-md block w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5 disabled:opacity-50"
>
- {intl.formatMessage(messages.selectQualityProfile)}
+ {isTesting
+ ? intl.formatMessage(messages.loadingprofiles)
+ : !isValidated
+ ? intl.formatMessage(
+ messages.testFirstQualityProfiles
+ )
+ : intl.formatMessage(messages.selectQualityProfile)}
{testResponse.profiles.length > 0 &&
testResponse.profiles.map((profile) => (
@@ -485,10 +500,15 @@ const SonarrModal: React.FC = ({
as="select"
id="rootFolder"
name="rootFolder"
- className="mt-1 form-select block rounded-md w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5"
+ disabled={!isValidated || isTesting}
+ className="mt-1 form-select block rounded-md w-full pl-3 pr-10 py-2 text-base leading-6 bg-gray-700 border-gray-500 focus:outline-none focus:ring-blue focus:border-gray-500 sm:text-sm sm:leading-5 disabled:opacity-50"
>
- {intl.formatMessage(messages.selectRootFolder)}
+ {isTesting
+ ? intl.formatMessage(messages.loadingrootfolders)
+ : !isValidated
+ ? intl.formatMessage(messages.testFirstRootFolders)
+ : intl.formatMessage(messages.selectRootFolder)}
{testResponse.rootFolders.length > 0 &&
testResponse.rootFolders.map((folder) => (
diff --git a/src/components/TitleCard/index.tsx b/src/components/TitleCard/index.tsx
index 443f06a1b..c460a9f90 100644
--- a/src/components/TitleCard/index.tsx
+++ b/src/components/TitleCard/index.tsx
@@ -21,7 +21,7 @@ interface TitleCardProps {
id: number;
image?: string;
summary?: string;
- year: string;
+ year?: string;
title: string;
userScore: number;
mediaType: MediaType;
@@ -169,7 +169,7 @@ const TitleCard: React.FC = ({
>
-
{year}
+ {year &&
{year}
}
{title}
diff --git a/src/components/TvDetails/index.tsx b/src/components/TvDetails/index.tsx
index 451a119f8..84e5fc156 100644
--- a/src/components/TvDetails/index.tsx
+++ b/src/components/TvDetails/index.tsx
@@ -227,8 +227,12 @@ const TvDetails: React.FC = ({ tv }) => {
)}
- {data.name}{' '}
- ({data.firstAirDate.slice(0, 4)})
+ {data.name}
+ {data.firstAirDate && (
+
+ ({data.firstAirDate.slice(0, 4)})
+
+ )}
{data.genres.map((g) => g.name).join(', ')}
diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json
index 8b1b27e39..f08ebcd5e 100644
--- a/src/i18n/locale/en.json
+++ b/src/i18n/locale/en.json
@@ -116,6 +116,8 @@
"components.Settings.RadarrModal.defaultserver": "Default Server",
"components.Settings.RadarrModal.editradarr": "Edit Radarr Server",
"components.Settings.RadarrModal.hostname": "Hostname",
+ "components.Settings.RadarrModal.loadingprofiles": "Loading quality profiles…",
+ "components.Settings.RadarrModal.loadingrootfolders": "Loading root folders…",
"components.Settings.RadarrModal.minimumAvailability": "Minimum Availability",
"components.Settings.RadarrModal.port": "Port",
"components.Settings.RadarrModal.qualityprofile": "Quality Profile",
@@ -130,11 +132,14 @@
"components.Settings.RadarrModal.servernamePlaceholder": "A Radarr Server",
"components.Settings.RadarrModal.ssl": "SSL",
"components.Settings.RadarrModal.test": "Test",
+ "components.Settings.RadarrModal.testFirstQualityProfiles": "Test your connection to load quality profiles",
+ "components.Settings.RadarrModal.testFirstRootFolders": "Test your connection to load root folders",
"components.Settings.RadarrModal.testing": "Testing...",
"components.Settings.RadarrModal.toastRadarrTestFailure": "Failed to connect to Radarr Server",
"components.Settings.RadarrModal.toastRadarrTestSuccess": "Radarr connection established!",
"components.Settings.RadarrModal.validationApiKeyRequired": "You must provide an API key",
"components.Settings.RadarrModal.validationHostnameRequired": "You must provide a hostname/IP",
+ "components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "You must select minimum availability",
"components.Settings.RadarrModal.validationNameRequired": "You must provide a server name",
"components.Settings.RadarrModal.validationPortRequired": "You must provide a port",
"components.Settings.RadarrModal.validationProfileRequired": "You must select a profile",
@@ -155,6 +160,8 @@
"components.Settings.SonarrModal.defaultserver": "Default Server",
"components.Settings.SonarrModal.editsonarr": "Edit Sonarr Server",
"components.Settings.SonarrModal.hostname": "Hostname",
+ "components.Settings.SonarrModal.loadingprofiles": "Loading quality profiles…",
+ "components.Settings.SonarrModal.loadingrootfolders": "Loading root folders…",
"components.Settings.SonarrModal.port": "Port",
"components.Settings.SonarrModal.qualityprofile": "Quality Profile",
"components.Settings.SonarrModal.rootfolder": "Root Folder",
@@ -168,6 +175,8 @@
"components.Settings.SonarrModal.servernamePlaceholder": "A Sonarr Server",
"components.Settings.SonarrModal.ssl": "SSL",
"components.Settings.SonarrModal.test": "Test",
+ "components.Settings.SonarrModal.testFirstQualityProfiles": "Test your connection to load quality profiles",
+ "components.Settings.SonarrModal.testFirstRootFolders": "Test your connection to load root folders",
"components.Settings.SonarrModal.testing": "Testing...",
"components.Settings.SonarrModal.toastRadarrTestFailure": "Could not connect to Sonarr Server",
"components.Settings.SonarrModal.toastRadarrTestSuccess": "Sonarr connection established!",
@@ -206,6 +215,9 @@
"components.Settings.menuPlexSettings": "Plex",
"components.Settings.menuServices": "Services",
"components.Settings.nextexecution": "Next Execution",
+ "components.Settings.no4kimplemented": "(Default 4K servers are not currently implemented)",
+ "components.Settings.nodefault": "No default server selected!",
+ "components.Settings.nodefaultdescription": "At least one server must be marked as default before any requests will make it to your services.",
"components.Settings.notificationsettings": "Notification Settings",
"components.Settings.notificationsettingsDescription": "Here you can pick and choose what types of notifications to send and through what types of services.",
"components.Settings.notrunning": "Not Running",
diff --git a/src/styles/globals.css b/src/styles/globals.css
index 18c2b0ff0..9df59f095 100644
--- a/src/styles/globals.css
+++ b/src/styles/globals.css
@@ -7,7 +7,7 @@ body {
}
.plex-button {
- @apply w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 transition ease-in-out duration-150 text-center;
+ @apply w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 transition ease-in-out duration-150 text-center disabled:opacity-50;
background-color: #cc7b19;
}