1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-25 22:46:31 -04:00

New: Import list clean library option

Closes #5201
This commit is contained in:
The Dark
2024-01-27 05:55:52 +00:00
committed by GitHub
parent 46367d2023
commit 68c326ae27
39 changed files with 1383 additions and 112 deletions
@@ -10,6 +10,7 @@ import translate from 'Utilities/String/translate';
import ImportListsExclusionsConnector from './ImportListExclusions/ImportListExclusionsConnector';
import ImportListsConnector from './ImportLists/ImportListsConnector';
import ManageImportListsModal from './ImportLists/Manage/ManageImportListsModal';
import ImportListOptions from './Options/ImportListOptions';
class ImportListSettings extends Component {
@@ -19,7 +20,10 @@ class ImportListSettings extends Component {
constructor(props, context) {
super(props, context);
this._saveCallback = null;
this.state = {
isSaving: false,
hasPendingChanges: false,
isManageImportListsOpen: false
};
@@ -28,6 +32,14 @@ class ImportListSettings extends Component {
//
// Listeners
setChildSave = (saveCallback) => {
this._saveCallback = saveCallback;
};
onChildStateChange = (payload) => {
this.setState(payload);
};
setListOptionsRef = (ref) => {
this._listOptions = ref;
};
@@ -47,7 +59,9 @@ class ImportListSettings extends Component {
};
onSavePress = () => {
this._listOptions.getWrappedInstance().save();
if (this._saveCallback) {
this._saveCallback();
}
};
//
@@ -93,6 +107,12 @@ class ImportListSettings extends Component {
<PageContentBody>
<ImportListsConnector />
<ImportListOptions
setChildSave={this.setChildSave}
onChildStateChange={this.onChildStateChange}
/>
<ImportListsExclusionsConnector />
<ManageImportListsModal
isOpen={isManageImportListsOpen}
@@ -0,0 +1,148 @@
import React, { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import {
fetchImportListOptions,
saveImportListOptions,
setImportListOptionsValue,
} from 'Store/Actions/settingsActions';
import createSettingsSectionSelector from 'Store/Selectors/createSettingsSectionSelector';
import translate from 'Utilities/String/translate';
const SECTION = 'importListOptions';
const cleanLibraryLevelOptions = [
{ key: 'disabled', value: () => translate('Disabled') },
{ key: 'logOnly', value: () => translate('LogOnly') },
{ key: 'keepAndUnmonitor', value: () => translate('KeepAndUnmonitorSeries') },
{ key: 'keepAndTag', value: () => translate('KeepAndTagSeries') },
];
function createImportListOptionsSelector() {
return createSelector(
(state: AppState) => state.settings.advancedSettings,
createSettingsSectionSelector(SECTION),
(advancedSettings, sectionSettings) => {
return {
advancedSettings,
save: sectionSettings.isSaving,
...sectionSettings,
};
}
);
}
interface ImportListOptionsPageProps {
setChildSave(saveCallback: () => void): void;
onChildStateChange(payload: unknown): void;
}
function ImportListOptions(props: ImportListOptionsPageProps) {
const { setChildSave, onChildStateChange } = props;
const selected = useSelector(createImportListOptionsSelector());
const {
isSaving,
hasPendingChanges,
advancedSettings,
isFetching,
error,
settings,
hasSettings,
} = selected;
const { listSyncLevel, listSyncTag } = settings;
const dispatch = useDispatch();
const onInputChange = useCallback(
({ name, value }: { name: string; value: unknown }) => {
// @ts-expect-error 'setImportListOptionsValue' isn't typed yet
dispatch(setImportListOptionsValue({ name, value }));
},
[dispatch]
);
const onTagChange = useCallback(
({ name, value }: { name: string; value: number[] }) => {
const id = value.length === 0 ? 0 : value.pop();
// @ts-expect-error 'setImportListOptionsValue' isn't typed yet
dispatch(setImportListOptionsValue({ name, value: id }));
},
[dispatch]
);
useEffect(() => {
dispatch(fetchImportListOptions());
setChildSave(() => dispatch(saveImportListOptions()));
return () => {
dispatch(clearPendingChanges({ section: SECTION }));
};
}, [dispatch, setChildSave]);
useEffect(() => {
onChildStateChange({
isSaving,
hasPendingChanges,
});
}, [onChildStateChange, isSaving, hasPendingChanges]);
const translatedLevelOptions = cleanLibraryLevelOptions.map(
({ key, value }) => {
return {
key,
value: value(),
};
}
);
return advancedSettings ? (
<FieldSet legend={translate('Options')}>
{isFetching ? <LoadingIndicator /> : null}
{!isFetching && error ? (
<div>{translate('UnableToLoadListOptions')}</div>
) : null}
{hasSettings && !isFetching && !error ? (
<Form>
<FormGroup advancedSettings={advancedSettings} isAdvanced={true}>
<FormLabel>{translate('CleanLibraryLevel')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="listSyncLevel"
values={translatedLevelOptions}
helpText={translate('ListSyncLevelHelpText')}
onChange={onInputChange}
{...listSyncLevel}
/>
</FormGroup>
{listSyncLevel.value === 'keepAndTag' ? (
<FormGroup advancedSettings={advancedSettings} isAdvanced={true}>
<FormLabel>{translate('ListSyncTag')}</FormLabel>
<FormInputGroup
{...listSyncTag}
type={inputTypes.TAG}
name="listSyncTag"
value={listSyncTag.value === 0 ? [] : [listSyncTag.value]}
helpText={translate('ListSyncTagHelpText')}
onChange={onTagChange}
/>
</FormGroup>
) : null}
</Form>
) : null}
</FieldSet>
) : null;
}
export default ImportListOptions;