1
0
mirror of https://github.com/Sonarr/Sonarr.git synced 2026-04-24 22:36:19 -04:00

New: Import list exclusion pagination

Closes #6079
This commit is contained in:
The Dark
2024-03-03 05:19:02 +00:00
committed by GitHub
parent de9899c60e
commit 4285691064
26 changed files with 663 additions and 690 deletions
@@ -1,27 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import Modal from 'Components/Modal/Modal';
import { sizes } from 'Helpers/Props';
import EditImportListExclusionModalContentConnector from './EditImportListExclusionModalContentConnector';
function EditImportListExclusionModal({ isOpen, onModalClose, ...otherProps }) {
return (
<Modal
size={sizes.MEDIUM}
isOpen={isOpen}
onModalClose={onModalClose}
>
<EditImportListExclusionModalContentConnector
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
EditImportListExclusionModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default EditImportListExclusionModal;
@@ -0,0 +1,41 @@
import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';
import Modal from 'Components/Modal/Modal';
import { sizes } from 'Helpers/Props';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import EditImportListExclusionModalContent from './EditImportListExclusionModalContent';
interface EditImportListExclusionModalProps {
id?: number;
isOpen: boolean;
onModalClose: () => void;
onDeleteImportListExclusionPress?: () => void;
}
function EditImportListExclusionModal(
props: EditImportListExclusionModalProps
) {
const { isOpen, onModalClose, ...otherProps } = props;
const dispatch = useDispatch();
const onModalClosePress = useCallback(() => {
dispatch(
clearPendingChanges({
section: 'settings.importListExclusions',
})
);
onModalClose();
}, [dispatch, onModalClose]);
return (
<Modal size={sizes.MEDIUM} isOpen={isOpen} onModalClose={onModalClosePress}>
<EditImportListExclusionModalContent
{...otherProps}
onModalClose={onModalClose}
/>
</Modal>
);
}
export default EditImportListExclusionModal;
@@ -1,43 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { clearPendingChanges } from 'Store/Actions/baseActions';
import EditImportListExclusionModal from './EditImportListExclusionModal';
function mapStateToProps() {
return {};
}
const mapDispatchToProps = {
clearPendingChanges
};
class EditImportListExclusionModalConnector extends Component {
//
// Listeners
onModalClose = () => {
this.props.clearPendingChanges({ section: 'settings.importListExclusions' });
this.props.onModalClose();
};
//
// Render
render() {
return (
<EditImportListExclusionModal
{...this.props}
onModalClose={this.onModalClose}
/>
);
}
}
EditImportListExclusionModalConnector.propTypes = {
onModalClose: PropTypes.func.isRequired,
clearPendingChanges: PropTypes.func.isRequired
};
export default connect(mapStateToProps, mapDispatchToProps)(EditImportListExclusionModalConnector);
@@ -1,139 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
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 Button from 'Components/Link/Button';
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import { numberSettingShape, stringSettingShape } from 'Helpers/Props/Shapes/settingShape';
import translate from 'Utilities/String/translate';
import styles from './EditImportListExclusionModalContent.css';
function EditImportListExclusionModalContent(props) {
const {
id,
isFetching,
error,
isSaving,
saveError,
item,
onInputChange,
onSavePress,
onModalClose,
onDeleteImportListExclusionPress,
...otherProps
} = props;
const {
title,
tvdbId
} = item;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{id ? translate('EditImportListExclusion') : translate('AddImportListExclusion')}
</ModalHeader>
<ModalBody className={styles.body}>
{
isFetching &&
<LoadingIndicator />
}
{
!isFetching && !!error &&
<Alert kind={kinds.DANGER}>
{translate('AddImportListExclusionError')}
</Alert>
}
{
!isFetching && !error &&
<Form
{...otherProps}
>
<FormGroup>
<FormLabel>{translate('Title')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="title"
helpText={translate('SeriesTitleToExcludeHelpText')}
{...title}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('TvdbId')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="tvdbId"
helpText={translate('TvdbIdExcludeHelpText')}
{...tvdbId}
onChange={onInputChange}
/>
</FormGroup>
</Form>
}
</ModalBody>
<ModalFooter>
{
id &&
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
onPress={onDeleteImportListExclusionPress}
>
{translate('Delete')}
</Button>
}
<Button
onPress={onModalClose}
>
{translate('Cancel')}
</Button>
<SpinnerErrorButton
isSpinning={isSaving}
error={saveError}
onPress={onSavePress}
>
{translate('Save')}
</SpinnerErrorButton>
</ModalFooter>
</ModalContent>
);
}
const ImportListExclusionShape = {
title: PropTypes.shape(stringSettingShape).isRequired,
tvdbId: PropTypes.shape(numberSettingShape).isRequired
};
EditImportListExclusionModalContent.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.shape(ImportListExclusionShape).isRequired,
onInputChange: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired,
onDeleteImportListExclusionPress: PropTypes.func
};
export default EditImportListExclusionModalContent;
@@ -0,0 +1,188 @@
import React, { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import AppState from 'App/State/AppState';
import Alert from 'Components/Alert';
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 Button from 'Components/Link/Button';
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import usePrevious from 'Helpers/Hooks/usePrevious';
import { inputTypes, kinds } from 'Helpers/Props';
import {
saveImportListExclusion,
setImportListExclusionValue,
} from 'Store/Actions/settingsActions';
import selectSettings from 'Store/Selectors/selectSettings';
import ImportListExclusion from 'typings/ImportListExclusion';
import { PendingSection } from 'typings/pending';
import translate from 'Utilities/String/translate';
import styles from './EditImportListExclusionModalContent.css';
const newImportListExclusion = {
title: '',
tvdbId: 0,
};
interface EditImportListExclusionModalContentProps {
id?: number;
onModalClose: () => void;
onDeleteImportListExclusionPress?: () => void;
}
function createImportListExclusionSelector(id?: number) {
return createSelector(
(state: AppState) => state.settings.importListExclusions,
(importListExclusions) => {
const { isFetching, error, isSaving, saveError, pendingChanges, items } =
importListExclusions;
const mapping = id
? items.find((i) => i.id === id)
: newImportListExclusion;
const settings = selectSettings(mapping, pendingChanges, saveError);
return {
id,
isFetching,
error,
isSaving,
saveError,
item: settings.settings as PendingSection<ImportListExclusion>,
...settings,
};
}
);
}
function EditImportListExclusionModalContent(
props: EditImportListExclusionModalContentProps
) {
const { id, onModalClose, onDeleteImportListExclusionPress } = props;
const dispatch = useDispatch();
const dispatchSetImportListExclusionValue = (payload: {
name: string;
value: string | number;
}) => {
// @ts-expect-error 'setImportListExclusionValue' isn't typed yet
dispatch(setImportListExclusionValue(payload));
};
const { isFetching, isSaving, item, error, saveError, ...otherProps } =
useSelector(createImportListExclusionSelector(props.id));
const previousIsSaving = usePrevious(isSaving);
const { title, tvdbId } = item;
useEffect(() => {
if (!id) {
Object.keys(newImportListExclusion).forEach((name) => {
dispatchSetImportListExclusionValue({
name,
value:
newImportListExclusion[name as keyof typeof newImportListExclusion],
});
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
if (previousIsSaving && !isSaving && !saveError) {
onModalClose();
}
});
const onSavePress = useCallback(() => {
dispatch(saveImportListExclusion({ id }));
}, [dispatch, id]);
const onInputChange = useCallback(
(payload: { name: string; value: string | number }) => {
// @ts-expect-error 'setImportListExclusionValue' isn't typed yet
dispatch(setImportListExclusionValue(payload));
},
[dispatch]
);
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{id
? translate('EditImportListExclusion')
: translate('AddImportListExclusion')}
</ModalHeader>
<ModalBody className={styles.body}>
{isFetching && <LoadingIndicator />}
{!isFetching && !!error && (
<Alert kind={kinds.DANGER}>
{translate('AddImportListExclusionError')}
</Alert>
)}
{!isFetching && !error && (
<Form {...otherProps}>
<FormGroup>
<FormLabel>{translate('Title')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="title"
helpText={translate('SeriesTitleToExcludeHelpText')}
{...title}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('TvdbId')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="tvdbId"
helpText={translate('TvdbIdExcludeHelpText')}
{...tvdbId}
onChange={onInputChange}
/>
</FormGroup>
</Form>
)}
</ModalBody>
<ModalFooter>
{id && (
<Button
className={styles.deleteButton}
kind={kinds.DANGER}
onPress={onDeleteImportListExclusionPress}
>
{translate('Delete')}
</Button>
)}
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<SpinnerErrorButton
isSpinning={isSaving}
error={saveError}
onPress={onSavePress}
>
{translate('Save')}
</SpinnerErrorButton>
</ModalFooter>
</ModalContent>
);
}
export default EditImportListExclusionModalContent;
@@ -1,117 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { saveImportListExclusion, setImportListExclusionValue } from 'Store/Actions/settingsActions';
import selectSettings from 'Store/Selectors/selectSettings';
import EditImportListExclusionModalContent from './EditImportListExclusionModalContent';
const newImportListExclusion = {
title: '',
tvdbId: 0
};
function createImportListExclusionSelector() {
return createSelector(
(state, { id }) => id,
(state) => state.settings.importListExclusions,
(id, importListExclusions) => {
const {
isFetching,
error,
isSaving,
saveError,
pendingChanges,
items
} = importListExclusions;
const mapping = id ? items.find((i) => i.id === id) : newImportListExclusion;
const settings = selectSettings(mapping, pendingChanges, saveError);
return {
id,
isFetching,
error,
isSaving,
saveError,
item: settings.settings,
...settings
};
}
);
}
function createMapStateToProps() {
return createSelector(
createImportListExclusionSelector(),
(importListExclusion) => {
return {
...importListExclusion
};
}
);
}
const mapDispatchToProps = {
setImportListExclusionValue,
saveImportListExclusion
};
class EditImportListExclusionModalContentConnector extends Component {
//
// Lifecycle
componentDidMount() {
if (!this.props.id) {
Object.keys(newImportListExclusion).forEach((name) => {
this.props.setImportListExclusionValue({
name,
value: newImportListExclusion[name]
});
});
}
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
this.props.onModalClose();
}
}
//
// Listeners
onInputChange = ({ name, value }) => {
this.props.setImportListExclusionValue({ name, value });
};
onSavePress = () => {
this.props.saveImportListExclusion({ id: this.props.id });
};
//
// Render
render() {
return (
<EditImportListExclusionModalContent
{...this.props}
onSavePress={this.onSavePress}
onInputChange={this.onInputChange}
/>
);
}
}
EditImportListExclusionModalContentConnector.propTypes = {
id: PropTypes.number,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.object.isRequired,
setImportListExclusionValue: PropTypes.func.isRequired,
saveImportListExclusion: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(EditImportListExclusionModalContentConnector);
@@ -1,25 +0,0 @@
.importListExclusion {
display: flex;
align-items: stretch;
margin-bottom: 10px;
height: 30px;
border-bottom: 1px solid var(--borderColor);
line-height: 30px;
}
.title {
@add-mixin truncate;
flex: 0 1 600px;
}
.tvdbId {
flex: 0 0 70px;
}
.actions {
display: flex;
justify-content: flex-end;
flex: 1 0 auto;
padding-right: 10px;
}
@@ -2,9 +2,6 @@
// Please do not change this file!
interface CssExports {
'actions': string;
'importListExclusion': string;
'title': string;
'tvdbId': string;
}
export const cssExports: CssExports;
export default cssExports;
@@ -1,112 +0,0 @@
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
import styles from './ImportListExclusion.css';
class ImportListExclusion extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isEditImportListExclusionModalOpen: false,
isDeleteImportListExclusionModalOpen: false
};
}
//
// Listeners
onEditImportListExclusionPress = () => {
this.setState({ isEditImportListExclusionModalOpen: true });
};
onEditImportListExclusionModalClose = () => {
this.setState({ isEditImportListExclusionModalOpen: false });
};
onDeleteImportListExclusionPress = () => {
this.setState({
isEditImportListExclusionModalOpen: false,
isDeleteImportListExclusionModalOpen: true
});
};
onDeleteImportListExclusionModalClose = () => {
this.setState({ isDeleteImportListExclusionModalOpen: false });
};
onConfirmDeleteImportListExclusion = () => {
this.props.onConfirmDeleteImportListExclusion(this.props.id);
};
//
// Render
render() {
const {
id,
title,
tvdbId
} = this.props;
return (
<div
className={classNames(
styles.importListExclusion
)}
>
<div className={styles.title}>{title}</div>
<div className={styles.tvdbId}>{tvdbId}</div>
<div className={styles.actions}>
<Link
onPress={this.onEditImportListExclusionPress}
>
<Icon name={icons.EDIT} />
</Link>
</div>
<EditImportListExclusionModalConnector
id={id}
isOpen={this.state.isEditImportListExclusionModalOpen}
onModalClose={this.onEditImportListExclusionModalClose}
onDeleteImportListExclusionPress={this.onDeleteImportListExclusionPress}
/>
<ConfirmModal
isOpen={this.state.isDeleteImportListExclusionModalOpen}
kind={kinds.DANGER}
title={translate('DeleteImportListExclusion')}
message={translate('DeleteImportListExclusionMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteImportListExclusion}
onCancel={this.onDeleteImportListExclusionModalClose}
/>
</div>
);
}
}
ImportListExclusion.propTypes = {
id: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
tvdbId: PropTypes.number.isRequired,
onConfirmDeleteImportListExclusion: PropTypes.func.isRequired
};
ImportListExclusion.defaultProps = {
// The drag preview will not connect the drag handle.
connectDragSource: (node) => node
};
export default ImportListExclusion;
@@ -0,0 +1,6 @@
.actions {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 35px;
white-space: nowrap;
}
@@ -0,0 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'actions': string;
}
export const cssExports: CssExports;
export default cssExports;
@@ -0,0 +1,68 @@
import React, { useCallback } from 'react';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import useModalOpenState from 'Helpers/Hooks/useModalOpenState';
import { icons, kinds } from 'Helpers/Props';
import ImportListExclusion from 'typings/ImportListExclusion';
import translate from 'Utilities/String/translate';
import EditImportListExclusionModal from './EditImportListExclusionModal';
import styles from './ImportListExclusionRow.css';
interface ImportListExclusionRowProps extends ImportListExclusion {
onConfirmDeleteImportListExclusion: (id: number) => void;
}
function ImportListExclusionRow(props: ImportListExclusionRowProps) {
const { id, title, tvdbId, onConfirmDeleteImportListExclusion } = props;
const [
isEditImportListExclusionModalOpen,
setEditImportListExclusionModalOpen,
setEditImportListExclusionModalClosed,
] = useModalOpenState(false);
const [
isDeleteImportListExclusionModalOpen,
setDeleteImportListExclusionModalOpen,
setDeleteImportListExclusionModalClosed,
] = useModalOpenState(false);
const onConfirmDeleteImportListExclusionPress = useCallback(() => {
onConfirmDeleteImportListExclusion(id);
}, [id, onConfirmDeleteImportListExclusion]);
return (
<TableRow>
<TableRowCell>{title}</TableRowCell>
<TableRowCell>{tvdbId}</TableRowCell>
<TableRowCell className={styles.actions}>
<IconButton
name={icons.EDIT}
onPress={setEditImportListExclusionModalOpen}
/>
</TableRowCell>
<EditImportListExclusionModal
id={id}
isOpen={isEditImportListExclusionModalOpen}
onModalClose={setEditImportListExclusionModalClosed}
onDeleteImportListExclusionPress={setDeleteImportListExclusionModalOpen}
/>
<ConfirmModal
isOpen={isDeleteImportListExclusionModalOpen}
kind={kinds.DANGER}
title={translate('DeleteImportListExclusion')}
message={translate('DeleteImportListExclusionMessageText')}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDeleteImportListExclusionPress}
onCancel={setDeleteImportListExclusionModalClosed}
/>
</TableRow>
);
}
export default ImportListExclusionRow;
@@ -1,23 +0,0 @@
.importListExclusionsHeader {
display: flex;
margin-bottom: 10px;
font-weight: bold;
}
.title {
flex: 0 1 600px;
}
.tvdbId {
flex: 0 0 70px;
}
.addImportListExclusion {
display: flex;
justify-content: flex-end;
padding-right: 10px;
}
.addButton {
text-align: center;
}
@@ -3,9 +3,6 @@
interface CssExports {
'addButton': string;
'addImportListExclusion': string;
'importListExclusionsHeader': string;
'title': string;
'tvdbId': string;
}
export const cssExports: CssExports;
export default cssExports;
@@ -1,105 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import FieldSet from 'Components/FieldSet';
import Icon from 'Components/Icon';
import Link from 'Components/Link/Link';
import PageSectionContent from 'Components/Page/PageSectionContent';
import { icons } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditImportListExclusionModalConnector from './EditImportListExclusionModalConnector';
import ImportListExclusion from './ImportListExclusion';
import styles from './ImportListExclusions.css';
class ImportListExclusions extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
isAddImportListExclusionModalOpen: false
};
}
//
// Listeners
onAddImportListExclusionPress = () => {
this.setState({ isAddImportListExclusionModalOpen: true });
};
onModalClose = () => {
this.setState({ isAddImportListExclusionModalOpen: false });
};
//
// Render
render() {
const {
items,
onConfirmDeleteImportListExclusion,
...otherProps
} = this.props;
return (
<FieldSet legend={translate('ImportListExclusions')}>
<PageSectionContent
errorMessage={translate('ImportListExclusionsLoadError')}
{...otherProps}
>
<div className={styles.importListExclusionsHeader}>
<div className={styles.title}>
{translate('Title')}
</div>
<div className={styles.tvdbId}>
{translate('TvdbId')}
</div>
</div>
<div>
{
items.map((item, index) => {
return (
<ImportListExclusion
key={item.id}
{...item}
{...otherProps}
index={index}
onConfirmDeleteImportListExclusion={onConfirmDeleteImportListExclusion}
/>
);
})
}
</div>
<div className={styles.addImportListExclusion}>
<Link
className={styles.addButton}
onPress={this.onAddImportListExclusionPress}
>
<Icon name={icons.ADD} />
</Link>
</div>
<EditImportListExclusionModalConnector
isOpen={this.state.isAddImportListExclusionModalOpen}
onModalClose={this.onModalClose}
/>
</PageSectionContent>
</FieldSet>
);
}
}
ImportListExclusions.propTypes = {
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
onConfirmDeleteImportListExclusion: PropTypes.func.isRequired
};
export default ImportListExclusions;
@@ -0,0 +1,234 @@
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 IconButton from 'Components/Link/IconButton';
import PageSectionContent from 'Components/Page/PageSectionContent';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TablePager from 'Components/Table/TablePager';
import TableRow from 'Components/Table/TableRow';
import useModalOpenState from 'Helpers/Hooks/useModalOpenState';
import { icons } from 'Helpers/Props';
import * as importListExclusionActions from 'Store/Actions/Settings/importListExclusions';
import {
registerPagePopulator,
unregisterPagePopulator,
} from 'Utilities/pagePopulator';
import translate from 'Utilities/String/translate';
import EditImportListExclusionModal from './EditImportListExclusionModal';
import ImportListExclusionRow from './ImportListExclusionRow';
const COLUMNS = [
{
name: 'title',
label: () => translate('Title'),
isVisible: true,
isSortable: true,
},
{
name: 'tvdbid',
label: () => translate('TvdbId'),
isVisible: true,
isSortable: true,
},
{
name: 'actions',
isVisible: true,
isSortable: false,
},
];
interface ImportListExclusionsProps {
useCurrentPage: number;
totalRecords: number;
}
function createImportListExlucionsSelector() {
return createSelector(
(state: AppState) => state.settings.importListExclusions,
(importListExclusions) => {
return {
...importListExclusions,
};
}
);
}
function ImportListExclusions(props: ImportListExclusionsProps) {
const { useCurrentPage, totalRecords } = props;
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 {
isFetching,
isPopulated,
items,
pageSize,
sortKey,
error,
sortDirection,
...otherProps
} = selected;
const [
isAddImportListExclusionModalOpen,
setAddImportListExclusionModalOpen,
setAddImportListExclusionModalClosed,
] = useModalOpenState(false);
const isFetchingForFirstTime = isFetching && !isPopulated;
return (
<FieldSet legend={translate('ImportListExclusions')}>
<PageSectionContent
errorMessage={translate('ImportListExclusionsLoadError')}
isFetching={isFetchingForFirstTime}
isPopulated={isPopulated}
error={error}
>
<Table
columns={COLUMNS}
canModifyColumns={false}
pageSize={pageSize}
sortKey={sortKey}
sortDirection={sortDirection}
onSortPress={setImportListExclusionSort}
onTableOptionChange={setImportListTableOption}
>
<TableBody>
{items.map((item) => {
return (
<ImportListExclusionRow
key={item.id}
{...item}
onConfirmDeleteImportListExclusion={
onConfirmDeleteImportListExclusion
}
/>
);
})}
<TableRow>
<TableRowCell />
<TableRowCell />
<TableRowCell>
<IconButton
name={icons.ADD}
onPress={setAddImportListExclusionModalOpen}
/>
</TableRowCell>
</TableRow>
</TableBody>
</Table>
<TablePager
totalRecords={totalRecords}
pageSize={pageSize}
isFetching={isFetching}
onFirstPagePress={gotoImportListExclusionFirstPage}
onPreviousPagePress={gotoImportListExclusionPreviousPage}
onNextPagePress={gotoImportListExclusionNextPage}
onLastPagePress={gotoImportListExclusionLastPage}
onPageSelect={gotoImportListExclusionPage}
{...otherProps}
/>
<EditImportListExclusionModal
isOpen={isAddImportListExclusionModalOpen}
onModalClose={setAddImportListExclusionModalClosed}
/>
</PageSectionContent>
</FieldSet>
);
}
export default ImportListExclusions;
@@ -1,59 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteImportListExclusion, fetchImportListExclusions } from 'Store/Actions/settingsActions';
import ImportListExclusions from './ImportListExclusions';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.importListExclusions,
(importListExclusions) => {
return {
...importListExclusions
};
}
);
}
const mapDispatchToProps = {
fetchImportListExclusions,
deleteImportListExclusion
};
class ImportListExclusionsConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.fetchImportListExclusions();
}
//
// Listeners
onConfirmDeleteImportListExclusion = (id) => {
this.props.deleteImportListExclusion({ id });
};
//
// Render
render() {
return (
<ImportListExclusions
{...this.state}
{...this.props}
onConfirmDeleteImportListExclusion={this.onConfirmDeleteImportListExclusion}
/>
);
}
}
ImportListExclusionsConnector.propTypes = {
fetchImportListExclusions: PropTypes.func.isRequired,
deleteImportListExclusion: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(ImportListExclusionsConnector);
@@ -7,7 +7,7 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { icons } from 'Helpers/Props';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import ImportListsExclusionsConnector from './ImportListExclusions/ImportListExclusionsConnector';
import ImportListsExclusions from './ImportListExclusions/ImportListExclusions';
import ImportListsConnector from './ImportLists/ImportListsConnector';
import ManageImportListsModal from './ImportLists/Manage/ManageImportListsModal';
import ImportListOptions from './Options/ImportListOptions';
@@ -113,7 +113,7 @@ class ImportListSettings extends Component {
onChildStateChange={this.onChildStateChange}
/>
<ImportListsExclusionsConnector />
<ImportListsExclusions />
<ManageImportListsModal
isOpen={isManageImportListsOpen}
onModalClose={this.onManageImportListsModalClose}