mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2026-04-25 22:59:10 -04:00
Fixed delete from mass editor
This commit is contained in:
+5
-5
@@ -1,9 +1,9 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import DeleteMovieModalContentConnector from './DeleteMovieModalContentConnector';
|
||||
import DeleteIndexerModalContentConnector from './DeleteIndexerModalContentConnector';
|
||||
|
||||
function DeleteMovieModal(props) {
|
||||
function DeleteIndexerModal(props) {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose,
|
||||
@@ -15,7 +15,7 @@ function DeleteMovieModal(props) {
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<DeleteMovieModalContentConnector
|
||||
<DeleteIndexerModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
@@ -23,9 +23,9 @@ function DeleteMovieModal(props) {
|
||||
);
|
||||
}
|
||||
|
||||
DeleteMovieModal.propTypes = {
|
||||
DeleteIndexerModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default DeleteMovieModal;
|
||||
export default DeleteIndexerModal;
|
||||
@@ -0,0 +1,74 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Button from 'Components/Link/Button';
|
||||
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 { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './DeleteIndexerModalContent.css';
|
||||
|
||||
class DeleteIndexerModalContent extends Component {
|
||||
onDeleteMovieConfirmed = () => {
|
||||
this.props.onDeleteSelectedPress();
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
indexers,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Delete Selected Indexers(s)
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
|
||||
<div className={styles.message}>
|
||||
{`Are you sure you want to delete ${indexers.length} selected indexers(s)`}
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
{
|
||||
indexers.map((s) => {
|
||||
return (
|
||||
<li key={s.name}>
|
||||
<span>{s.name}</span>
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
{translate('Cancel')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
kind={kinds.DANGER}
|
||||
onPress={this.onDeleteMovieConfirmed}
|
||||
>
|
||||
{translate('Delete')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteIndexerModalContent.propTypes = {
|
||||
indexers: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
onDeleteSelectedPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default DeleteIndexerModalContent;
|
||||
@@ -0,0 +1,43 @@
|
||||
import _ from 'lodash';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { bulkDeleteIndexers } from 'Store/Actions/indexerIndexActions';
|
||||
import createAllIndexersSelector from 'Store/Selectors/createAllIndexersSelector';
|
||||
import DeleteIndexerModalContent from './DeleteIndexerModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state, { indexerIds }) => indexerIds,
|
||||
createAllIndexersSelector(),
|
||||
(indexerIds, allIndexers) => {
|
||||
const selectedMovie = _.intersectionWith(allIndexers, indexerIds, (s, id) => {
|
||||
return s.id === id;
|
||||
});
|
||||
|
||||
const sortedMovies = _.orderBy(selectedMovie, 'name');
|
||||
const indexers = _.map(sortedMovies, (s) => {
|
||||
return {
|
||||
name: s.name
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
indexers
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
onDeleteSelectedPress() {
|
||||
dispatch(bulkDeleteIndexers({
|
||||
indexerIds: props.indexerIds
|
||||
}));
|
||||
|
||||
props.onModalClose();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(DeleteIndexerModalContent);
|
||||
@@ -1,145 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
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 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 translate from 'Utilities/String/translate';
|
||||
import styles from './DeleteMovieModalContent.css';
|
||||
|
||||
class DeleteMovieModalContent extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
deleteFiles: false,
|
||||
addImportExclusion: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onDeleteFilesChange = ({ value }) => {
|
||||
this.setState({ deleteFiles: value });
|
||||
}
|
||||
|
||||
onAddImportExclusionChange = ({ value }) => {
|
||||
this.setState({ addImportExclusion: value });
|
||||
}
|
||||
|
||||
onDeleteMovieConfirmed = () => {
|
||||
const deleteFiles = this.state.deleteFiles;
|
||||
const addImportExclusion = this.state.addImportExclusion;
|
||||
|
||||
this.setState({ deleteFiles: false, addImportExclusion: false });
|
||||
this.props.onDeleteSelectedPress(deleteFiles, addImportExclusion);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
movies,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
const deleteFiles = this.state.deleteFiles;
|
||||
const addImportExclusion = this.state.addImportExclusion;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Delete Selected Movie(s)
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<div>
|
||||
<FormGroup>
|
||||
<FormLabel>{`Delete Movie Folder${movies.length > 1 ? 's' : ''}`}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="deleteFiles"
|
||||
value={deleteFiles}
|
||||
helpText={`Delete Movie Folder${movies.length > 1 ? 's' : ''} and all contents`}
|
||||
kind={kinds.DANGER}
|
||||
onChange={this.onDeleteFilesChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('AddListExclusion')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="addImportExclusion"
|
||||
value={addImportExclusion}
|
||||
helpText={translate('AddImportExclusionHelpText')}
|
||||
kind={kinds.DANGER}
|
||||
onChange={this.onAddImportExclusionChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</div>
|
||||
|
||||
<div className={styles.message}>
|
||||
{`Are you sure you want to delete ${movies.length} selected movie(s)${deleteFiles ? ' and all contents' : ''}?`}
|
||||
</div>
|
||||
|
||||
<ul>
|
||||
{
|
||||
movies.map((s) => {
|
||||
return (
|
||||
<li key={s.title}>
|
||||
<span>{s.title}</span>
|
||||
|
||||
{
|
||||
deleteFiles &&
|
||||
<span className={styles.pathContainer}>
|
||||
-
|
||||
<span className={styles.path}>
|
||||
{s.path}
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
{translate('Cancel')}
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
kind={kinds.DANGER}
|
||||
onPress={this.onDeleteMovieConfirmed}
|
||||
>
|
||||
{translate('Delete')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteMovieModalContent.propTypes = {
|
||||
movies: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
onDeleteSelectedPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default DeleteMovieModalContent;
|
||||
@@ -1,46 +0,0 @@
|
||||
import _ from 'lodash';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { bulkDeleteMovie } from 'Store/Actions/indexerIndexActions';
|
||||
import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector';
|
||||
import DeleteMovieModalContent from './DeleteMovieModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state, { movieIds }) => movieIds,
|
||||
createAllMoviesSelector(),
|
||||
(movieIds, allMovies) => {
|
||||
const selectedMovie = _.intersectionWith(allMovies, movieIds, (s, id) => {
|
||||
return s.id === id;
|
||||
});
|
||||
|
||||
const sortedMovies = _.orderBy(selectedMovie, 'sortTitle');
|
||||
const movies = _.map(sortedMovies, (s) => {
|
||||
return {
|
||||
title: s.title,
|
||||
path: s.path
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
movies
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
onDeleteSelectedPress(deleteFiles, addImportExclusion) {
|
||||
dispatch(bulkDeleteMovie({
|
||||
movieIds: props.movieIds,
|
||||
deleteFiles,
|
||||
addImportExclusion
|
||||
}));
|
||||
|
||||
props.onModalClose();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(DeleteMovieModalContent);
|
||||
+12
-12
@@ -4,14 +4,14 @@ import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import DeleteMovieModal from './Delete/DeleteMovieModal';
|
||||
import MovieEditorFooterLabel from './MovieEditorFooterLabel';
|
||||
import DeleteIndexerModal from './Delete/DeleteIndexerModal';
|
||||
import IndexerEditorFooterLabel from './IndexerEditorFooterLabel';
|
||||
import TagsModal from './Tags/TagsModal';
|
||||
import styles from './MovieEditorFooter.css';
|
||||
import styles from './IndexerEditorFooter.css';
|
||||
|
||||
const NO_CHANGE = 'noChange';
|
||||
|
||||
class MovieEditorFooter extends Component {
|
||||
class IndexerEditorFooter extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
@@ -88,7 +88,7 @@ class MovieEditorFooter extends Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
movieIds,
|
||||
indexerIds,
|
||||
selectedCount,
|
||||
isSaving,
|
||||
isDeleting
|
||||
@@ -104,7 +104,7 @@ class MovieEditorFooter extends Component {
|
||||
<PageContentFooter>
|
||||
<div className={styles.buttonContainer}>
|
||||
<div className={styles.buttonContainerContent}>
|
||||
<MovieEditorFooterLabel
|
||||
<IndexerEditorFooterLabel
|
||||
label={translate('IndexersSelectedInterp', [selectedCount])}
|
||||
isSaving={false}
|
||||
/>
|
||||
@@ -136,14 +136,14 @@ class MovieEditorFooter extends Component {
|
||||
|
||||
<TagsModal
|
||||
isOpen={isTagsModalOpen}
|
||||
movieIds={movieIds}
|
||||
indexerIds={indexerIds}
|
||||
onApplyTagsPress={this.onApplyTagsPress}
|
||||
onModalClose={this.onTagsModalClose}
|
||||
/>
|
||||
|
||||
<DeleteMovieModal
|
||||
<DeleteIndexerModal
|
||||
isOpen={isDeleteMovieModalOpen}
|
||||
movieIds={movieIds}
|
||||
indexerIds={indexerIds}
|
||||
onModalClose={this.onDeleteMovieModalClose}
|
||||
/>
|
||||
</PageContentFooter>
|
||||
@@ -151,8 +151,8 @@ class MovieEditorFooter extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
MovieEditorFooter.propTypes = {
|
||||
movieIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
IndexerEditorFooter.propTypes = {
|
||||
indexerIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
selectedCount: PropTypes.number.isRequired,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
saveError: PropTypes.object,
|
||||
@@ -161,4 +161,4 @@ MovieEditorFooter.propTypes = {
|
||||
onSaveSelected: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default MovieEditorFooter;
|
||||
export default IndexerEditorFooter;
|
||||
+5
-5
@@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import SpinnerIcon from 'Components/SpinnerIcon';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import styles from './MovieEditorFooterLabel.css';
|
||||
import styles from './IndexerEditorFooterLabel.css';
|
||||
|
||||
function MovieEditorFooterLabel(props) {
|
||||
function IndexerEditorFooterLabel(props) {
|
||||
const {
|
||||
className,
|
||||
label,
|
||||
@@ -27,14 +27,14 @@ function MovieEditorFooterLabel(props) {
|
||||
);
|
||||
}
|
||||
|
||||
MovieEditorFooterLabel.propTypes = {
|
||||
IndexerEditorFooterLabel.propTypes = {
|
||||
className: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
isSaving: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
MovieEditorFooterLabel.defaultProps = {
|
||||
IndexerEditorFooterLabel.defaultProps = {
|
||||
className: styles.label
|
||||
};
|
||||
|
||||
export default MovieEditorFooterLabel;
|
||||
export default IndexerEditorFooterLabel;
|
||||
@@ -1,17 +1,17 @@
|
||||
import _ from 'lodash';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector';
|
||||
import createAllIndexersSelector from 'Store/Selectors/createAllIndexersSelector';
|
||||
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
||||
import TagsModalContent from './TagsModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state, { movieIds }) => movieIds,
|
||||
createAllMoviesSelector(),
|
||||
(state, { indexerIds }) => indexerIds,
|
||||
createAllIndexersSelector(),
|
||||
createTagsSelector(),
|
||||
(movieIds, allMovies, tagList) => {
|
||||
const movies = _.intersectionWith(allMovies, movieIds, (s, id) => {
|
||||
(indexerIds, allMovies, tagList) => {
|
||||
const movies = _.intersectionWith(allMovies, indexerIds, (s, id) => {
|
||||
return s.id === id;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user