This commit is contained in:
Bogdan 2024-08-11 16:52:47 +00:00 committed by GitHub
commit 69d722a5ef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 286 additions and 164 deletions

View File

@ -66,7 +66,9 @@ function Table(props) {
columns.map((column) => { columns.map((column) => {
const { const {
name, name,
isVisible isVisible,
isSortable,
...otherColumnProps
} = column; } = column;
if (!isVisible) { if (!isVisible) {
@ -84,6 +86,7 @@ function Table(props) {
name={name} name={name}
isSortable={false} isSortable={false}
{...otherProps} {...otherProps}
{...otherColumnProps}
> >
<TableOptionsModalWrapper <TableOptionsModalWrapper
columns={columns} columns={columns}

View File

@ -1,7 +0,0 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'actions': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@ -1,21 +1,28 @@
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import IconButton from 'Components/Link/IconButton'; import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal'; import ConfirmModal from 'Components/Modal/ConfirmModal';
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow'; import TableRow from 'Components/Table/TableRow';
import useModalOpenState from 'Helpers/Hooks/useModalOpenState'; import useModalOpenState from 'Helpers/Hooks/useModalOpenState';
import { icons, kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
import { deleteImportListExclusion } from 'Store/Actions/Settings/importListExclusions';
import ImportListExclusion from 'typings/ImportListExclusion'; import ImportListExclusion from 'typings/ImportListExclusion';
import { SelectStateInputProps } from 'typings/props';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import EditImportListExclusionModal from './EditImportListExclusionModal'; import EditImportListExclusionModal from './EditImportListExclusionModal';
import styles from './ImportListExclusionRow.css'; import styles from './ImportListExclusionRow.css';
interface ImportListExclusionRowProps extends ImportListExclusion { interface ImportListExclusionRowProps extends ImportListExclusion {
onConfirmDeleteImportListExclusion: (id: number) => void; isSelected: boolean;
onSelectedChange: (options: SelectStateInputProps) => void;
} }
function ImportListExclusionRow(props: ImportListExclusionRowProps) { function ImportListExclusionRow(props: ImportListExclusionRowProps) {
const { id, title, tvdbId, onConfirmDeleteImportListExclusion } = props; const { id, tvdbId, title, isSelected, onSelectedChange } = props;
const dispatch = useDispatch();
const [ const [
isEditImportListExclusionModalOpen, isEditImportListExclusionModalOpen,
@ -29,12 +36,18 @@ function ImportListExclusionRow(props: ImportListExclusionRowProps) {
setDeleteImportListExclusionModalClosed, setDeleteImportListExclusionModalClosed,
] = useModalOpenState(false); ] = useModalOpenState(false);
const onConfirmDeleteImportListExclusionPress = useCallback(() => { const handleDeletePress = useCallback(() => {
onConfirmDeleteImportListExclusion(id); dispatch(deleteImportListExclusion({ id }));
}, [id, onConfirmDeleteImportListExclusion]); }, [id, dispatch]);
return ( return (
<TableRow> <TableRow>
<TableSelectCell
id={id}
isSelected={isSelected}
onSelectedChange={onSelectedChange}
/>
<TableRowCell>{title}</TableRowCell> <TableRowCell>{title}</TableRowCell>
<TableRowCell>{tvdbId}</TableRowCell> <TableRowCell>{tvdbId}</TableRowCell>
@ -58,7 +71,7 @@ function ImportListExclusionRow(props: ImportListExclusionRowProps) {
title={translate('DeleteImportListExclusion')} title={translate('DeleteImportListExclusion')}
message={translate('DeleteImportListExclusionMessageText')} message={translate('DeleteImportListExclusionMessageText')}
confirmLabel={translate('Delete')} confirmLabel={translate('Delete')}
onConfirm={onConfirmDeleteImportListExclusionPress} onConfirm={handleDeletePress}
onCancel={setDeleteImportListExclusionModalClosed} onCancel={setDeleteImportListExclusionModalClosed}
/> />
</TableRow> </TableRow>

View File

@ -0,0 +1,6 @@
.actions {
composes: headerCell from '~Components/Table/TableHeaderCell.css';
width: 35px;
white-space: nowrap;
}

View File

@ -1,8 +1,7 @@
// This file is automatically generated. // This file is automatically generated.
// Please do not change this file! // Please do not change this file!
interface CssExports { interface CssExports {
'addButton': string; 'actions': string;
'addImportListExclusion': string;
} }
export const cssExports: CssExports; export const cssExports: CssExports;
export default cssExports; export default cssExports;

View File

@ -1,28 +1,46 @@
import React, { useCallback, useEffect } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { useHistory } from 'react-router';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import AppState from 'App/State/AppState'; import AppState from 'App/State/AppState';
import FieldSet from 'Components/FieldSet'; import FieldSet from 'Components/FieldSet';
import IconButton from 'Components/Link/IconButton'; import IconButton from 'Components/Link/IconButton';
import SpinnerButton from 'Components/Link/SpinnerButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageSectionContent from 'Components/Page/PageSectionContent'; import PageSectionContent from 'Components/Page/PageSectionContent';
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import Column from 'Components/Table/Column';
import Table from 'Components/Table/Table'; import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody'; import TableBody from 'Components/Table/TableBody';
import TablePager from 'Components/Table/TablePager'; import TablePager from 'Components/Table/TablePager';
import TableRow from 'Components/Table/TableRow'; import TableRow from 'Components/Table/TableRow';
import usePaging from 'Components/Table/usePaging';
import useCurrentPage from 'Helpers/Hooks/useCurrentPage';
import useModalOpenState from 'Helpers/Hooks/useModalOpenState'; import useModalOpenState from 'Helpers/Hooks/useModalOpenState';
import { icons } from 'Helpers/Props'; import usePrevious from 'Helpers/Hooks/usePrevious';
import * as importListExclusionActions from 'Store/Actions/Settings/importListExclusions'; import useSelectState from 'Helpers/Hooks/useSelectState';
import { icons, kinds } from 'Helpers/Props';
import {
bulkDeleteImportListExclusions,
clearImportListExclusions,
fetchImportListExclusions,
gotoImportListExclusionPage,
setImportListExclusionSort,
setImportListExclusionTableOption,
} from 'Store/Actions/Settings/importListExclusions';
import { CheckInputChanged } from 'typings/inputs';
import { SelectStateInputProps } from 'typings/props';
import { TableOptionsChangePayload } from 'typings/Table';
import { import {
registerPagePopulator, registerPagePopulator,
unregisterPagePopulator, unregisterPagePopulator,
} from 'Utilities/pagePopulator'; } from 'Utilities/pagePopulator';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import EditImportListExclusionModal from './EditImportListExclusionModal'; import EditImportListExclusionModal from './EditImportListExclusionModal';
import ImportListExclusionRow from './ImportListExclusionRow'; import ImportListExclusionRow from './ImportListExclusionRow';
import styles from './ImportListExclusions.css';
const COLUMNS = [ const COLUMNS: Column[] = [
{ {
name: 'title', name: 'title',
label: () => translate('Title'), label: () => translate('Title'),
@ -36,13 +54,15 @@ const COLUMNS = [
isSortable: true, isSortable: true,
}, },
{ {
className: styles.actions,
name: 'actions', name: 'actions',
label: '',
isVisible: true, isVisible: true,
isSortable: false, isSortable: false,
}, },
]; ];
function createImportListExlucionsSelector() { function createImportListExclusionsSelector() {
return createSelector( return createSelector(
(state: AppState) => state.settings.importListExclusions, (state: AppState) => state.settings.importListExclusions,
(importListExclusions) => { (importListExclusions) => {
@ -54,95 +74,7 @@ function createImportListExlucionsSelector() {
} }
function ImportListExclusions() { function ImportListExclusions() {
const history = useHistory(); const requestCurrentPage = useCurrentPage();
const useCurrentPage = history.action === 'POP';
const dispatch = useDispatch();
const fetchImportListExclusions = useCallback(() => {
dispatch(importListExclusionActions.fetchImportListExclusions());
}, [dispatch]);
const deleteImportListExclusion = useCallback(
(payload: { id: number }) => {
dispatch(importListExclusionActions.deleteImportListExclusion(payload));
},
[dispatch]
);
const gotoImportListExclusionFirstPage = useCallback(() => {
dispatch(importListExclusionActions.gotoImportListExclusionFirstPage());
}, [dispatch]);
const gotoImportListExclusionPreviousPage = useCallback(() => {
dispatch(importListExclusionActions.gotoImportListExclusionPreviousPage());
}, [dispatch]);
const gotoImportListExclusionNextPage = useCallback(() => {
dispatch(importListExclusionActions.gotoImportListExclusionNextPage());
}, [dispatch]);
const gotoImportListExclusionLastPage = useCallback(() => {
dispatch(importListExclusionActions.gotoImportListExclusionLastPage());
}, [dispatch]);
const gotoImportListExclusionPage = useCallback(
(page: number) => {
dispatch(
importListExclusionActions.gotoImportListExclusionPage({ page })
);
},
[dispatch]
);
const setImportListExclusionSort = useCallback(
(sortKey: { sortKey: string }) => {
dispatch(
importListExclusionActions.setImportListExclusionSort({ sortKey })
);
},
[dispatch]
);
const setImportListTableOption = useCallback(
(payload: { pageSize: number }) => {
dispatch(
importListExclusionActions.setImportListExclusionTableOption(payload)
);
if (payload.pageSize) {
dispatch(importListExclusionActions.gotoImportListExclusionFirstPage());
}
},
[dispatch]
);
const repopulate = useCallback(() => {
gotoImportListExclusionFirstPage();
}, [gotoImportListExclusionFirstPage]);
useEffect(() => {
registerPagePopulator(repopulate);
if (useCurrentPage) {
fetchImportListExclusions();
} else {
gotoImportListExclusionFirstPage();
}
return () => unregisterPagePopulator(repopulate);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const onConfirmDeleteImportListExclusion = useCallback(
(id: number) => {
deleteImportListExclusion({ id });
repopulate();
},
[deleteImportListExclusion, repopulate]
);
const selected = useSelector(createImportListExlucionsSelector());
const { const {
isFetching, isFetching,
@ -152,9 +84,127 @@ function ImportListExclusions() {
sortKey, sortKey,
error, error,
sortDirection, sortDirection,
page,
totalPages,
totalRecords, totalRecords,
...otherProps isDeleting,
} = selected; deleteError,
} = useSelector(createImportListExclusionsSelector());
const dispatch = useDispatch();
const [isConfirmDeleteModalOpen, setIsConfirmDeleteModalOpen] =
useState(false);
const previousIsDeleting = usePrevious(isDeleting);
const [selectState, setSelectState] = useSelectState();
const { allSelected, allUnselected, selectedState } = selectState;
const selectedIds = useMemo(() => {
return getSelectedIds(selectedState);
}, [selectedState]);
const handleSelectAllChange = useCallback(
({ value }: CheckInputChanged) => {
setSelectState({ type: value ? 'selectAll' : 'unselectAll', items });
},
[items, setSelectState]
);
const handleSelectedChange = useCallback(
({ id, value, shiftKey = false }: SelectStateInputProps) => {
setSelectState({
type: 'toggleSelected',
items,
id,
isSelected: value,
shiftKey,
});
},
[items, setSelectState]
);
const handleDeleteSelectedPress = useCallback(() => {
setIsConfirmDeleteModalOpen(true);
}, [setIsConfirmDeleteModalOpen]);
const handleDeleteSelectedConfirmed = useCallback(() => {
dispatch(bulkDeleteImportListExclusions({ ids: selectedIds }));
setIsConfirmDeleteModalOpen(false);
}, [selectedIds, setIsConfirmDeleteModalOpen, dispatch]);
const handleConfirmDeleteModalClose = useCallback(() => {
setIsConfirmDeleteModalOpen(false);
}, [setIsConfirmDeleteModalOpen]);
const {
handleFirstPagePress,
handlePreviousPagePress,
handleNextPagePress,
handleLastPagePress,
handlePageSelect,
} = usePaging({
page,
totalPages,
gotoPage: gotoImportListExclusionPage,
});
const handleSortPress = useCallback(
(sortKey: { sortKey: string }) => {
dispatch(setImportListExclusionSort({ sortKey }));
},
[dispatch]
);
const handleTableOptionChange = useCallback(
(payload: TableOptionsChangePayload) => {
dispatch(setImportListExclusionTableOption(payload));
if (payload.pageSize) {
dispatch(gotoImportListExclusionPage({ page: 1 }));
}
},
[dispatch]
);
useEffect(() => {
if (requestCurrentPage) {
dispatch(fetchImportListExclusions());
} else {
dispatch(gotoImportListExclusionPage({ page: 1 }));
}
return () => {
dispatch(clearImportListExclusions());
};
}, [requestCurrentPage, dispatch]);
useEffect(() => {
const repopulate = () => {
dispatch(fetchImportListExclusions());
};
registerPagePopulator(repopulate);
return () => {
unregisterPagePopulator(repopulate);
};
}, [dispatch]);
useEffect(() => {
if (previousIsDeleting && !isDeleting && !deleteError) {
setSelectState({ type: 'unselectAll', items });
dispatch(fetchImportListExclusions());
}
}, [
previousIsDeleting,
isDeleting,
deleteError,
items,
dispatch,
setSelectState,
]);
const [ const [
isAddImportListExclusionModalOpen, isAddImportListExclusionModalOpen,
@ -173,13 +223,17 @@ function ImportListExclusions() {
error={error} error={error}
> >
<Table <Table
selectAll={true}
allSelected={allSelected}
allUnselected={allUnselected}
columns={COLUMNS} columns={COLUMNS}
canModifyColumns={false} canModifyColumns={false}
pageSize={pageSize} pageSize={pageSize}
sortKey={sortKey} sortKey={sortKey}
sortDirection={sortDirection} sortDirection={sortDirection}
onSortPress={setImportListExclusionSort} onTableOptionChange={handleTableOptionChange}
onTableOptionChange={setImportListTableOption} onSelectAllChange={handleSelectAllChange}
onSortPress={handleSortPress}
> >
<TableBody> <TableBody>
{items.map((item) => { {items.map((item) => {
@ -187,16 +241,23 @@ function ImportListExclusions() {
<ImportListExclusionRow <ImportListExclusionRow
key={item.id} key={item.id}
{...item} {...item}
onConfirmDeleteImportListExclusion={ isSelected={selectedState[item.id] || false}
onConfirmDeleteImportListExclusion onSelectedChange={handleSelectedChange}
}
/> />
); );
})} })}
<TableRow> <TableRow>
<TableRowCell /> <TableRowCell colSpan={3}>
<TableRowCell /> <SpinnerButton
kind={kinds.DANGER}
isSpinning={isDeleting}
isDisabled={!selectedIds.length}
onPress={handleDeleteSelectedPress}
>
{translate('Delete')}
</SpinnerButton>
</TableRowCell>
<TableRowCell> <TableRowCell>
<IconButton <IconButton
@ -209,21 +270,31 @@ function ImportListExclusions() {
</Table> </Table>
<TablePager <TablePager
page={page}
totalPages={totalPages}
totalRecords={totalRecords} totalRecords={totalRecords}
pageSize={pageSize}
isFetching={isFetching} isFetching={isFetching}
onFirstPagePress={gotoImportListExclusionFirstPage} onFirstPagePress={handleFirstPagePress}
onPreviousPagePress={gotoImportListExclusionPreviousPage} onPreviousPagePress={handlePreviousPagePress}
onNextPagePress={gotoImportListExclusionNextPage} onNextPagePress={handleNextPagePress}
onLastPagePress={gotoImportListExclusionLastPage} onLastPagePress={handleLastPagePress}
onPageSelect={gotoImportListExclusionPage} onPageSelect={handlePageSelect}
{...otherProps}
/> />
<EditImportListExclusionModal <EditImportListExclusionModal
isOpen={isAddImportListExclusionModalOpen} isOpen={isAddImportListExclusionModalOpen}
onModalClose={setAddImportListExclusionModalClosed} onModalClose={setAddImportListExclusionModalClosed}
/> />
<ConfirmModal
isOpen={isConfirmDeleteModalOpen}
kind={kinds.DANGER}
title={translate('DeleteSelected')}
message={translate('DeleteSelectedImportListExclusionsMessageText')}
confirmLabel={translate('DeleteSelected')}
onConfirm={handleDeleteSelectedConfirmed}
onCancel={handleConfirmDeleteModalClose}
/>
</PageSectionContent> </PageSectionContent>
</FieldSet> </FieldSet>
); );

View File

@ -7,7 +7,7 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector'; import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import ImportListsExclusions from './ImportListExclusions/ImportListExclusions'; import ImportListExclusions from './ImportListExclusions/ImportListExclusions';
import ImportListsConnector from './ImportLists/ImportListsConnector'; import ImportListsConnector from './ImportLists/ImportListsConnector';
import ManageImportListsModal from './ImportLists/Manage/ManageImportListsModal'; import ManageImportListsModal from './ImportLists/Manage/ManageImportListsModal';
import ImportListOptions from './Options/ImportListOptions'; import ImportListOptions from './Options/ImportListOptions';
@ -113,7 +113,8 @@ class ImportListSettings extends Component {
onChildStateChange={this.onChildStateChange} onChildStateChange={this.onChildStateChange}
/> />
<ImportListsExclusions /> <ImportListExclusions />
<ManageImportListsModal <ManageImportListsModal
isOpen={isManageImportListsOpen} isOpen={isManageImportListsOpen}
onModalClose={this.onManageImportListsModalClose} onModalClose={this.onManageImportListsModalClose}

View File

@ -21,7 +21,7 @@ const mapDispatchToProps = {
fetchRootFolders fetchRootFolders
}; };
class ListsConnector extends Component { class ImportListsConnector extends Component {
// //
// Lifecycle // Lifecycle
@ -51,10 +51,10 @@ class ListsConnector extends Component {
} }
} }
ListsConnector.propTypes = { ImportListsConnector.propTypes = {
fetchImportLists: PropTypes.func.isRequired, fetchImportLists: PropTypes.func.isRequired,
deleteImportList: PropTypes.func.isRequired, deleteImportList: PropTypes.func.isRequired,
fetchRootFolders: PropTypes.func.isRequired fetchRootFolders: PropTypes.func.isRequired
}; };
export default connect(createMapStateToProps, mapDispatchToProps)(ListsConnector); export default connect(createMapStateToProps, mapDispatchToProps)(ImportListsConnector);

View File

@ -48,7 +48,6 @@ interface ImportListOptionsPageProps {
function ImportListOptions(props: ImportListOptionsPageProps) { function ImportListOptions(props: ImportListOptionsPageProps) {
const { setChildSave, onChildStateChange } = props; const { setChildSave, onChildStateChange } = props;
const selected = useSelector(createImportListOptionsSelector());
const { const {
isSaving, isSaving,
@ -58,7 +57,7 @@ function ImportListOptions(props: ImportListOptionsPageProps) {
error, error,
settings, settings,
hasSettings, hasSettings,
} = selected; } = useSelector(createImportListOptionsSelector());
const { listSyncLevel, listSyncTag } = settings; const { listSyncLevel, listSyncTag } = settings;

View File

@ -1,7 +1,9 @@
import { createAction } from 'redux-actions'; import { createAction } from 'redux-actions';
import createBulkRemoveItemHandler from 'Store/Actions/Creators/createBulkRemoveItemHandler';
import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler'; import createRemoveItemHandler from 'Store/Actions/Creators/createRemoveItemHandler';
import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler'; import createSaveProviderHandler from 'Store/Actions/Creators/createSaveProviderHandler';
import createServerSideCollectionHandlers from 'Store/Actions/Creators/createServerSideCollectionHandlers'; import createServerSideCollectionHandlers from 'Store/Actions/Creators/createServerSideCollectionHandlers';
import createClearReducer from 'Store/Actions/Creators/Reducers/createClearReducer';
import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer'; import createSetSettingValueReducer from 'Store/Actions/Creators/Reducers/createSetSettingValueReducer';
import createSetTableOptionReducer from 'Store/Actions/Creators/Reducers/createSetTableOptionReducer'; import createSetTableOptionReducer from 'Store/Actions/Creators/Reducers/createSetTableOptionReducer';
import { createThunk, handleThunks } from 'Store/thunks'; import { createThunk, handleThunks } from 'Store/thunks';
@ -16,29 +18,26 @@ const section = 'settings.importListExclusions';
// Actions Types // Actions Types
export const FETCH_IMPORT_LIST_EXCLUSIONS = 'settings/importListExclusions/fetchImportListExclusions'; export const FETCH_IMPORT_LIST_EXCLUSIONS = 'settings/importListExclusions/fetchImportListExclusions';
export const GOTO_FIRST_IMPORT_LIST_EXCLUSION_PAGE = 'settings/importListExclusions/gotoImportListExclusionFirstPage';
export const GOTO_PREVIOUS_IMPORT_LIST_EXCLUSION_PAGE = 'settings/importListExclusions/gotoImportListExclusionPreviousPage';
export const GOTO_NEXT_IMPORT_LIST_EXCLUSION_PAGE = 'settings/importListExclusions/gotoImportListExclusionNextPage';
export const GOTO_LAST_IMPORT_LIST_EXCLUSION_PAGE = 'settings/importListExclusions/gotoImportListExclusionLastPage';
export const GOTO_IMPORT_LIST_EXCLUSION_PAGE = 'settings/importListExclusions/gotoImportListExclusionPage'; export const GOTO_IMPORT_LIST_EXCLUSION_PAGE = 'settings/importListExclusions/gotoImportListExclusionPage';
export const SET_IMPORT_LIST_EXCLUSION_SORT = 'settings/importListExclusions/setImportListExclusionSort'; export const SET_IMPORT_LIST_EXCLUSION_SORT = 'settings/importListExclusions/setImportListExclusionSort';
export const SET_IMPORT_LIST_EXCLUSION_TABLE_OPTION = 'settings/importListExclusions/setImportListExclusionTableOption';
export const SAVE_IMPORT_LIST_EXCLUSION = 'settings/importListExclusions/saveImportListExclusion'; export const SAVE_IMPORT_LIST_EXCLUSION = 'settings/importListExclusions/saveImportListExclusion';
export const DELETE_IMPORT_LIST_EXCLUSION = 'settings/importListExclusions/deleteImportListExclusion'; export const DELETE_IMPORT_LIST_EXCLUSION = 'settings/importListExclusions/deleteImportListExclusion';
export const BULK_DELETE_IMPORT_LIST_EXCLUSIONS = 'settings/importListExclusions/bulkDeleteImportListExclusions';
export const CLEAR_IMPORT_LIST_EXCLUSIONS = 'settings/importListExclusions/clearImportListExclusions';
export const SET_IMPORT_LIST_EXCLUSION_TABLE_OPTION = 'settings/importListExclusions/setImportListExclusionTableOption';
export const SET_IMPORT_LIST_EXCLUSION_VALUE = 'settings/importListExclusions/setImportListExclusionValue'; export const SET_IMPORT_LIST_EXCLUSION_VALUE = 'settings/importListExclusions/setImportListExclusionValue';
// //
// Action Creators // Action Creators
export const fetchImportListExclusions = createThunk(FETCH_IMPORT_LIST_EXCLUSIONS); export const fetchImportListExclusions = createThunk(FETCH_IMPORT_LIST_EXCLUSIONS);
export const gotoImportListExclusionFirstPage = createThunk(GOTO_FIRST_IMPORT_LIST_EXCLUSION_PAGE);
export const gotoImportListExclusionPreviousPage = createThunk(GOTO_PREVIOUS_IMPORT_LIST_EXCLUSION_PAGE);
export const gotoImportListExclusionNextPage = createThunk(GOTO_NEXT_IMPORT_LIST_EXCLUSION_PAGE);
export const gotoImportListExclusionLastPage = createThunk(GOTO_LAST_IMPORT_LIST_EXCLUSION_PAGE);
export const gotoImportListExclusionPage = createThunk(GOTO_IMPORT_LIST_EXCLUSION_PAGE); export const gotoImportListExclusionPage = createThunk(GOTO_IMPORT_LIST_EXCLUSION_PAGE);
export const setImportListExclusionSort = createThunk(SET_IMPORT_LIST_EXCLUSION_SORT); export const setImportListExclusionSort = createThunk(SET_IMPORT_LIST_EXCLUSION_SORT);
export const saveImportListExclusion = createThunk(SAVE_IMPORT_LIST_EXCLUSION); export const saveImportListExclusion = createThunk(SAVE_IMPORT_LIST_EXCLUSION);
export const deleteImportListExclusion = createThunk(DELETE_IMPORT_LIST_EXCLUSION); export const deleteImportListExclusion = createThunk(DELETE_IMPORT_LIST_EXCLUSION);
export const bulkDeleteImportListExclusions = createThunk(BULK_DELETE_IMPORT_LIST_EXCLUSIONS);
export const clearImportListExclusions = createAction(CLEAR_IMPORT_LIST_EXCLUSIONS);
export const setImportListExclusionTableOption = createAction(SET_IMPORT_LIST_EXCLUSION_TABLE_OPTION); export const setImportListExclusionTableOption = createAction(SET_IMPORT_LIST_EXCLUSION_TABLE_OPTION);
export const setImportListExclusionValue = createAction(SET_IMPORT_LIST_EXCLUSION_VALUE, (payload) => { export const setImportListExclusionValue = createAction(SET_IMPORT_LIST_EXCLUSION_VALUE, (payload) => {
@ -64,6 +63,8 @@ export default {
items: [], items: [],
isSaving: false, isSaving: false,
saveError: null, saveError: null,
isDeleting: false,
deleteError: null,
pendingChanges: {} pendingChanges: {}
}, },
@ -77,16 +78,13 @@ export default {
fetchImportListExclusions, fetchImportListExclusions,
{ {
[serverSideCollectionHandlers.FETCH]: FETCH_IMPORT_LIST_EXCLUSIONS, [serverSideCollectionHandlers.FETCH]: FETCH_IMPORT_LIST_EXCLUSIONS,
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_IMPORT_LIST_EXCLUSION_PAGE,
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_IMPORT_LIST_EXCLUSION_PAGE,
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_IMPORT_LIST_EXCLUSION_PAGE,
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_IMPORT_LIST_EXCLUSION_PAGE,
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_IMPORT_LIST_EXCLUSION_PAGE, [serverSideCollectionHandlers.EXACT_PAGE]: GOTO_IMPORT_LIST_EXCLUSION_PAGE,
[serverSideCollectionHandlers.SORT]: SET_IMPORT_LIST_EXCLUSION_SORT [serverSideCollectionHandlers.SORT]: SET_IMPORT_LIST_EXCLUSION_SORT
} }
), ),
[SAVE_IMPORT_LIST_EXCLUSION]: createSaveProviderHandler(section, '/importlistexclusion'), [SAVE_IMPORT_LIST_EXCLUSION]: createSaveProviderHandler(section, '/importlistexclusion'),
[DELETE_IMPORT_LIST_EXCLUSION]: createRemoveItemHandler(section, '/importlistexclusion') [DELETE_IMPORT_LIST_EXCLUSION]: createRemoveItemHandler(section, '/importlistexclusion'),
[BULK_DELETE_IMPORT_LIST_EXCLUSIONS]: createBulkRemoveItemHandler(section, '/importlistexclusion/bulk')
}), }),
// //
@ -94,7 +92,19 @@ export default {
reducers: { reducers: {
[SET_IMPORT_LIST_EXCLUSION_VALUE]: createSetSettingValueReducer(section), [SET_IMPORT_LIST_EXCLUSION_VALUE]: createSetSettingValueReducer(section),
[SET_IMPORT_LIST_EXCLUSION_TABLE_OPTION]: createSetTableOptionReducer(section) [SET_IMPORT_LIST_EXCLUSION_TABLE_OPTION]: createSetTableOptionReducer(section),
[CLEAR_IMPORT_LIST_EXCLUSIONS]: createClearReducer(section, {
isFetching: false,
isPopulated: false,
error: null,
items: [],
isDeleting: false,
deleteError: null,
pendingChanges: {},
totalPages: 0,
totalRecords: 0
})
} }
}; };

View File

@ -20,19 +20,19 @@ const section = 'settings.importLists';
// //
// Actions Types // Actions Types
export const FETCH_IMPORT_LISTS = 'settings/importlists/fetchImportLists'; export const FETCH_IMPORT_LISTS = 'settings/importLists/fetchImportLists';
export const FETCH_IMPORT_LIST_SCHEMA = 'settings/importlists/fetchImportListSchema'; export const FETCH_IMPORT_LIST_SCHEMA = 'settings/importLists/fetchImportListSchema';
export const SELECT_IMPORT_LIST_SCHEMA = 'settings/importlists/selectImportListSchema'; export const SELECT_IMPORT_LIST_SCHEMA = 'settings/importLists/selectImportListSchema';
export const SET_IMPORT_LIST_VALUE = 'settings/importlists/setImportListValue'; export const SET_IMPORT_LIST_VALUE = 'settings/importLists/setImportListValue';
export const SET_IMPORT_LIST_FIELD_VALUE = 'settings/importlists/setImportListFieldValue'; export const SET_IMPORT_LIST_FIELD_VALUE = 'settings/importLists/setImportListFieldValue';
export const SAVE_IMPORT_LIST = 'settings/importlists/saveImportList'; export const SAVE_IMPORT_LIST = 'settings/importLists/saveImportList';
export const CANCEL_SAVE_IMPORT_LIST = 'settings/importlists/cancelSaveImportList'; export const CANCEL_SAVE_IMPORT_LIST = 'settings/importLists/cancelSaveImportList';
export const DELETE_IMPORT_LIST = 'settings/importlists/deleteImportList'; export const DELETE_IMPORT_LIST = 'settings/importLists/deleteImportList';
export const TEST_IMPORT_LIST = 'settings/importlists/testImportList'; export const TEST_IMPORT_LIST = 'settings/importLists/testImportList';
export const CANCEL_TEST_IMPORT_LIST = 'settings/importlists/cancelTestImportList'; export const CANCEL_TEST_IMPORT_LIST = 'settings/importLists/cancelTestImportList';
export const TEST_ALL_IMPORT_LISTS = 'settings/importlists/testAllImportLists'; export const TEST_ALL_IMPORT_LISTS = 'settings/importLists/testAllImportLists';
export const BULK_EDIT_IMPORT_LISTS = 'settings/importlists/bulkEditImportLists'; export const BULK_EDIT_IMPORT_LISTS = 'settings/importLists/bulkEditImportLists';
export const BULK_DELETE_IMPORT_LISTS = 'settings/importlists/bulkDeleteImportLists'; export const BULK_DELETE_IMPORT_LISTS = 'settings/importLists/bulkDeleteImportLists';
// //
// Action Creators // Action Creators

View File

@ -12,6 +12,7 @@ namespace NzbDrone.Core.ImportLists.Exclusions
List<ImportListExclusion> All(); List<ImportListExclusion> All();
PagingSpec<ImportListExclusion> Paged(PagingSpec<ImportListExclusion> pagingSpec); PagingSpec<ImportListExclusion> Paged(PagingSpec<ImportListExclusion> pagingSpec);
void Delete(int id); void Delete(int id);
void Delete(List<int> ids);
ImportListExclusion Get(int id); ImportListExclusion Get(int id);
ImportListExclusion FindByTvdbId(int tvdbId); ImportListExclusion FindByTvdbId(int tvdbId);
ImportListExclusion Update(ImportListExclusion importListExclusion); ImportListExclusion Update(ImportListExclusion importListExclusion);
@ -41,6 +42,11 @@ namespace NzbDrone.Core.ImportLists.Exclusions
_repo.Delete(id); _repo.Delete(id);
} }
public void Delete(List<int> ids)
{
_repo.DeleteMany(ids);
}
public ImportListExclusion Get(int id) public ImportListExclusion Get(int id)
{ {
return _repo.Get(id); return _repo.Get(id);

View File

@ -363,10 +363,12 @@
"DeleteRemotePathMappingMessageText": "Are you sure you want to delete this remote path mapping?", "DeleteRemotePathMappingMessageText": "Are you sure you want to delete this remote path mapping?",
"DeleteRootFolder": "Delete Root Folder", "DeleteRootFolder": "Delete Root Folder",
"DeleteRootFolderMessageText": "Are you sure you want to delete the root folder '{path}'?", "DeleteRootFolderMessageText": "Are you sure you want to delete the root folder '{path}'?",
"DeleteSelected": "Delete Selected",
"DeleteSelectedDownloadClients": "Delete Download Client(s)", "DeleteSelectedDownloadClients": "Delete Download Client(s)",
"DeleteSelectedDownloadClientsMessageText": "Are you sure you want to delete {count} selected download client(s)?", "DeleteSelectedDownloadClientsMessageText": "Are you sure you want to delete {count} selected download client(s)?",
"DeleteSelectedEpisodeFiles": "Delete Selected Episode Files", "DeleteSelectedEpisodeFiles": "Delete Selected Episode Files",
"DeleteSelectedEpisodeFilesHelpText": "Are you sure you want to delete the selected episode files?", "DeleteSelectedEpisodeFilesHelpText": "Are you sure you want to delete the selected episode files?",
"DeleteSelectedImportListExclusionsMessageText": "Are you sure you want to delete the selected import list exclusions?",
"DeleteSelectedImportLists": "Delete Import List(s)", "DeleteSelectedImportLists": "Delete Import List(s)",
"DeleteSelectedImportListsMessageText": "Are you sure you want to delete {count} selected import list(s)?", "DeleteSelectedImportListsMessageText": "Are you sure you want to delete {count} selected import list(s)?",
"DeleteSelectedIndexers": "Delete Indexer(s)", "DeleteSelectedIndexers": "Delete Indexer(s)",
@ -1787,8 +1789,8 @@
"SeasonPremieresOnly": "Season Premieres Only", "SeasonPremieresOnly": "Season Premieres Only",
"Seasons": "Seasons", "Seasons": "Seasons",
"SeasonsMonitoredAll": "All", "SeasonsMonitoredAll": "All",
"SeasonsMonitoredPartial": "Partial",
"SeasonsMonitoredNone": "None", "SeasonsMonitoredNone": "None",
"SeasonsMonitoredPartial": "Partial",
"SeasonsMonitoredStatus": "Seasons Monitored", "SeasonsMonitoredStatus": "Seasons Monitored",
"SecretToken": "Secret Token", "SecretToken": "Secret Token",
"Security": "Security", "Security": "Security",

View File

@ -0,0 +1,9 @@
using System.Collections.Generic;
namespace Sonarr.Api.V3.ImportLists
{
public class ImportListExclusionBulkResource
{
public HashSet<int> Ids { get; set; }
}
}

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using FluentValidation; using FluentValidation;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using NzbDrone.Core.ImportLists.Exclusions; using NzbDrone.Core.ImportLists.Exclusions;
@ -65,9 +66,18 @@ namespace Sonarr.Api.V3.ImportLists
} }
[RestDeleteById] [RestDeleteById]
public void DeleteImportListExclusionResource(int id) public void DeleteImportListExclusion(int id)
{ {
_importListExclusionService.Delete(id); _importListExclusionService.Delete(id);
} }
[HttpDelete("bulk")]
[Produces("application/json")]
public object DeleteImportListExclusions([FromBody] ImportListExclusionBulkResource resource)
{
_importListExclusionService.Delete(resource.Ids.ToList());
return new { };
}
} }
} }