feat(ui): add option to only allow complete series requests (#1164)

pull/1197/head^2
TheCatLady 4 years ago committed by GitHub
parent 6f1a31de47
commit 36c00fde27
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -125,6 +125,9 @@ components:
hideAvailable:
type: boolean
example: false
partialRequestsEnabled:
type: boolean
example: false
localLogin:
type: boolean
example: true

@ -14,6 +14,7 @@ export interface PublicSettingsResponse {
series4kEnabled: boolean;
region: string;
originalLanguage: string;
partialRequestsEnabled: boolean;
}
export interface CacheItem {

@ -72,6 +72,7 @@ export interface MainSettings {
region: string;
originalLanguage: string;
trustProxy: boolean;
partialRequestsEnabled: boolean;
}
interface PublicSettings {
@ -86,6 +87,7 @@ interface FullPublicSettings extends PublicSettings {
series4kEnabled: boolean;
region: string;
originalLanguage: string;
partialRequestsEnabled: boolean;
}
export interface NotificationAgentConfig {
@ -199,6 +201,7 @@ class Settings {
region: '',
originalLanguage: '',
trustProxy: false,
partialRequestsEnabled: true,
},
plex: {
name: '',
@ -345,6 +348,7 @@ class Settings {
),
region: this.data.main.region,
originalLanguage: this.data.main.originalLanguage,
partialRequestsEnabled: this.data.main.partialRequestsEnabled,
};
}

@ -19,6 +19,7 @@ import SeasonRequest from '../../../server/entity/SeasonRequest';
import Alert from '../Common/Alert';
import AdvancedRequester, { RequestOverrides } from './AdvancedRequester';
import SearchByNameModal from './SearchByNameModal';
import useSettings from '../../hooks/useSettings';
const messages = defineMessages({
requestadmin: 'Your request will be immediately approved.',
@ -30,7 +31,9 @@ const messages = defineMessages({
requesting: 'Requesting…',
requestseasons:
'Request {seasonCount} {seasonCount, plural, one {Season} other {Seasons}}',
selectseason: 'Select season(s)',
requestall: 'Request All Seasons',
alreadyrequested: 'Already Requested',
selectseason: 'Select Season(s)',
season: 'Season',
numberofepisodes: '# of Episodes',
status: 'Status',
@ -63,6 +66,7 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
editRequest,
is4k = false,
}) => {
const settings = useSettings();
const { addToast } = useToasts();
const editingSeasons: number[] = (editRequest?.seasons ?? []).map(
(season) => season.seasonNumber
@ -135,9 +139,13 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
};
const sendRequest = async () => {
if (selectedSeasons.length === 0) {
if (
settings.currentSettings.partialRequestsEnabled &&
selectedSeasons.length === 0
) {
return;
}
if (onUpdating) {
onUpdating(true);
}
@ -158,7 +166,11 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
tvdbId: tvdbId ?? data?.externalIds.tvdbId,
mediaType: 'tv',
is4k,
seasons: selectedSeasons,
seasons: settings.currentSettings.partialRequestsEnabled
? selectedSeasons
: getAllSeasons().filter(
(season) => !getAllRequestedSeasons().includes(season)
),
...overrideParams,
});
@ -190,6 +202,12 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
}
};
const getAllSeasons = (): number[] => {
return (data?.seasons ?? [])
.filter((season) => season.seasonNumber !== 0)
.map((season) => season.seasonNumber);
};
const getAllRequestedSeasons = (): number[] => {
const requestedSeasons = (data?.mediaInfo?.requests ?? [])
.filter(
@ -243,19 +261,14 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
data &&
selectedSeasons.length >= 0 &&
selectedSeasons.length <
data?.seasons
.filter((season) => season.seasonNumber !== 0)
.filter(
(season) => !getAllRequestedSeasons().includes(season.seasonNumber)
).length
getAllSeasons().filter(
(season) => !getAllRequestedSeasons().includes(season)
).length
) {
setSelectedSeasons(
data.seasons
.filter((season) => season.seasonNumber !== 0)
.filter(
(season) => !getAllRequestedSeasons().includes(season.seasonNumber)
)
.map((season) => season.seasonNumber)
getAllSeasons().filter(
(season) => !getAllRequestedSeasons().includes(season)
)
);
} else {
setSelectedSeasons([]);
@ -268,11 +281,9 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
}
return (
selectedSeasons.length ===
data.seasons
.filter((season) => season.seasonNumber !== 0)
.filter(
(season) => !getAllRequestedSeasons().includes(season.seasonNumber)
).length
getAllSeasons().filter(
(season) => !getAllRequestedSeasons().includes(season)
).length
);
};
@ -329,15 +340,29 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
okText={
editRequest && selectedSeasons.length === 0
? 'Cancel Request'
: getAllRequestedSeasons().length >= getAllSeasons().length
? intl.formatMessage(messages.alreadyrequested)
: !settings.currentSettings.partialRequestsEnabled
? intl.formatMessage(messages.requestall)
: selectedSeasons.length === 0
? intl.formatMessage(messages.selectseason)
: intl.formatMessage(messages.requestseasons, {
seasonCount: selectedSeasons.length,
})
}
okDisabled={editRequest ? false : selectedSeasons.length === 0}
okDisabled={
editRequest
? false
: getAllRequestedSeasons().length >= getAllSeasons().length ||
(settings.currentSettings.partialRequestsEnabled &&
selectedSeasons.length === 0)
}
okButtonType={
editRequest && selectedSeasons.length === 0 ? 'danger' : `primary`
editRequest &&
settings.currentSettings.partialRequestsEnabled &&
selectedSeasons.length === 0
? 'danger'
: `primary`
}
cancelText={
tvdbId
@ -361,13 +386,15 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
</svg>
}
>
{(hasPermission(Permission.MANAGE_REQUESTS) ||
hasPermission(
is4k ? Permission.AUTO_APPROVE_4K : Permission.AUTO_APPROVE
) ||
hasPermission(
is4k ? Permission.AUTO_APPROVE_4K_TV : Permission.AUTO_APPROVE_TV
)) &&
{hasPermission(
[
Permission.MANAGE_REQUESTS,
is4k ? Permission.AUTO_APPROVE_4K : Permission.AUTO_APPROVE,
is4k ? Permission.AUTO_APPROVE_4K_TV : Permission.AUTO_APPROVE_TV,
],
{ type: 'or' }
) &&
getAllRequestedSeasons().length < getAllSeasons().length &&
!editRequest && (
<p className="mt-6">
<Alert
@ -385,7 +412,12 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
<table className="min-w-full">
<thead>
<tr>
<th className="w-16 px-4 py-3 bg-gray-500">
<th
className={`w-16 px-4 py-3 bg-gray-500 ${
!settings.currentSettings.partialRequestsEnabled &&
'hidden'
}`}
>
<span
role="checkbox"
tabIndex={0}
@ -438,7 +470,12 @@ const TvRequestModal: React.FC<RequestModalProps> = ({
);
return (
<tr key={`season-${season.id}`}>
<td className="px-4 py-4 text-sm font-medium leading-5 text-gray-100 whitespace-nowrap">
<td
className={`px-4 py-4 text-sm font-medium leading-5 text-gray-100 whitespace-nowrap ${
!settings.currentSettings
.partialRequestsEnabled && 'hidden'
}`}
>
<span
role="checkbox"
tabIndex={0}

@ -46,6 +46,7 @@ const messages = defineMessages({
validationApplicationUrl: 'You must provide a valid URL',
validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash',
originalLanguageDefault: 'All Languages',
partialRequestsEnabled: 'Enable Partial Series Requests',
});
const SettingsMain: React.FC = () => {
@ -116,6 +117,7 @@ const SettingsMain: React.FC = () => {
hideAvailable: data?.hideAvailable,
region: data?.region,
originalLanguage: data?.originalLanguage,
partialRequestsEnabled: data?.partialRequestsEnabled,
trustProxy: data?.trustProxy,
}}
enableReinitialize
@ -129,6 +131,7 @@ const SettingsMain: React.FC = () => {
hideAvailable: values.hideAvailable,
region: values.region,
originalLanguage: values.originalLanguage,
partialRequestsEnabled: values.partialRequestsEnabled,
trustProxy: values.trustProxy,
});
@ -338,6 +341,29 @@ const SettingsMain: React.FC = () => {
/>
</div>
</div>
<div className="form-row">
<label
htmlFor="partialRequestsEnabled"
className="checkbox-label"
>
<span className="mr-2">
{intl.formatMessage(messages.partialRequestsEnabled)}
</span>
</label>
<div className="form-input">
<Field
type="checkbox"
id="partialRequestsEnabled"
name="partialRequestsEnabled"
onChange={() => {
setFieldValue(
'partialRequestsEnabled',
!values.partialRequestsEnabled
);
}}
/>
</div>
</div>
<div className="actions">
<div className="flex justify-end">
<span className="inline-flex ml-3 rounded-md shadow-sm">

@ -10,11 +10,12 @@ const defaultSettings = {
initialized: false,
applicationTitle: 'Overseerr',
hideAvailable: false,
localLogin: false,
localLogin: true,
movie4kEnabled: false,
series4kEnabled: false,
region: '',
originalLanguage: '',
partialRequestsEnabled: true,
};
export const SettingsContext = React.createContext<SettingsContextProps>({

@ -213,6 +213,7 @@
"components.RequestModal.SearchByNameModal.nosummary": "No summary for this title was found.",
"components.RequestModal.SearchByNameModal.notvdbid": "Manual Match Required",
"components.RequestModal.SearchByNameModal.notvdbiddescription": "We couldn't automatically match your request. Please select the correct match from the list below:",
"components.RequestModal.alreadyrequested": "Already Requested",
"components.RequestModal.autoapproval": "Automatic Approval",
"components.RequestModal.backbutton": "Back",
"components.RequestModal.cancel": "Cancel Request",
@ -233,6 +234,7 @@
"components.RequestModal.requestCancel": "Request for <strong>{title}</strong> canceled.",
"components.RequestModal.requestSuccess": "<strong>{title}</strong> requested.",
"components.RequestModal.requestadmin": "Your request will be immediately approved.",
"components.RequestModal.requestall": "Request All Seasons",
"components.RequestModal.requestcancelled": "Request canceled.",
"components.RequestModal.requestedited": "Request edited.",
"components.RequestModal.requesterror": "Something went wrong while submitting the request.",
@ -242,7 +244,7 @@
"components.RequestModal.requesttitle": "Request {title}",
"components.RequestModal.season": "Season",
"components.RequestModal.seasonnumber": "Season {number}",
"components.RequestModal.selectseason": "Select season(s)",
"components.RequestModal.selectseason": "Select Season(s)",
"components.RequestModal.status": "Status",
"components.ResetPassword.confirmpassword": "Confirm Password",
"components.ResetPassword.email": "Email Address",
@ -557,6 +559,7 @@
"components.Settings.originalLanguageDefault": "All Languages",
"components.Settings.originallanguage": "Discover Language",
"components.Settings.originallanguageTip": "Filter content by original language (only applies to the \"Popular\" and \"Upcoming\" categories)",
"components.Settings.partialRequestsEnabled": "Enable Partial Series Requests",
"components.Settings.plexlibraries": "Plex Libraries",
"components.Settings.plexlibrariesDescription": "The libraries Overseerr scans for titles. Set up and save your Plex connection settings, then click the button below if no libraries are listed.",
"components.Settings.plexsettings": "Plex Settings",

@ -148,6 +148,7 @@ CoreApp.getInitialProps = async (initialProps) => {
localLogin: true,
region: '',
originalLanguage: '',
partialRequestsEnabled: true,
};
let locale = 'en';

Loading…
Cancel
Save