parent
dd5b35e590
commit
191d06deca
@ -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);
|
@ -0,0 +1,12 @@
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
function createAllIndexersSelector() {
|
||||
return createSelector(
|
||||
(state) => state.indexers,
|
||||
(indexers) => {
|
||||
return indexers.items;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default createAllIndexersSelector;
|
@ -1,12 +0,0 @@
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
function createAllMoviesSelector() {
|
||||
return createSelector(
|
||||
(state) => state.movies,
|
||||
(movies) => {
|
||||
return movies.items;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default createAllMoviesSelector;
|
@ -0,0 +1,30 @@
|
||||
using Nancy;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using Prowlarr.Http.Extensions;
|
||||
|
||||
namespace Prowlarr.Api.V1.Indexers
|
||||
{
|
||||
public class IndexerEditorModule : ProwlarrV1Module
|
||||
{
|
||||
private readonly IIndexerFactory _movieService;
|
||||
private readonly IManageCommandQueue _commandQueueManager;
|
||||
|
||||
public IndexerEditorModule(IIndexerFactory movieService, IManageCommandQueue commandQueueManager)
|
||||
: base("/indexer/editor")
|
||||
{
|
||||
_movieService = movieService;
|
||||
_commandQueueManager = commandQueueManager;
|
||||
Delete("/", movie => DeleteIndexers());
|
||||
}
|
||||
|
||||
private object DeleteIndexers()
|
||||
{
|
||||
var resource = Request.Body.FromJson<IndexerEditorResource>();
|
||||
|
||||
_movieService.DeleteIndexers(resource.IndexerIds);
|
||||
|
||||
return new object();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Prowlarr.Api.V1.Indexers
|
||||
{
|
||||
public class IndexerEditorResource
|
||||
{
|
||||
public List<int> IndexerIds { get; set; }
|
||||
}
|
||||
}
|
Loading…
Reference in new issue