New: Bulk select episodes in Manual Import
This commit is contained in:
parent
079a0b56c3
commit
63141f339f
|
@ -80,6 +80,7 @@ class SelectEpisodeModalContent extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
|
ids,
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
|
@ -99,6 +100,13 @@ class SelectEpisodeModalContent extends Component {
|
||||||
|
|
||||||
const errorMessage = getErrorMessage(error, 'Unable to load episodes');
|
const errorMessage = getErrorMessage(error, 'Unable to load episodes');
|
||||||
|
|
||||||
|
const selectedFilesCount = ids.length;
|
||||||
|
const selectedCount = this.getSelectedIds().length;
|
||||||
|
const selectionIsValid = (
|
||||||
|
selectedCount > 0 &&
|
||||||
|
selectedCount % selectedFilesCount === 0
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalContent onModalClose={onModalClose}>
|
<ModalContent onModalClose={onModalClose}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
|
@ -158,18 +166,25 @@ class SelectEpisodeModalContent extends Component {
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
|
|
||||||
<ModalFooter className={styles.footer}>
|
<ModalFooter className={styles.footer}>
|
||||||
<div className={styles.path}>{relativePath}</div>
|
<div className={styles.path}>
|
||||||
|
{
|
||||||
|
relativePath ?
|
||||||
|
relativePath :
|
||||||
|
`${selectedFilesCount} selected files`
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className={styles.buttons}>
|
<div className={styles.buttons}>
|
||||||
<Button onPress={onModalClose}>
|
<Button onPress={onModalClose}>
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
kind={kinds.SUCCESS}
|
kind={kinds.SUCCESS}
|
||||||
|
isDisabled={!selectionIsValid}
|
||||||
onPress={this.onEpisodesSelect}
|
onPress={this.onEpisodesSelect}
|
||||||
>
|
>
|
||||||
Select Episodes
|
Select Episodes
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
|
@ -179,11 +194,12 @@ class SelectEpisodeModalContent extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectEpisodeModalContent.propTypes = {
|
SelectEpisodeModalContent.propTypes = {
|
||||||
|
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
relativePath: PropTypes.string.isRequired,
|
relativePath: PropTypes.string,
|
||||||
sortKey: PropTypes.string,
|
sortKey: PropTypes.string,
|
||||||
sortDirection: PropTypes.string,
|
sortDirection: PropTypes.string,
|
||||||
onSortPress: PropTypes.func.isRequired,
|
onSortPress: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
@ -56,7 +55,13 @@ class SelectEpisodeModalContentConnector extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onEpisodesSelect = (episodeIds) => {
|
onEpisodesSelect = (episodeIds) => {
|
||||||
const episodes = _.reduce(this.props.items, (acc, item) => {
|
const {
|
||||||
|
ids,
|
||||||
|
items,
|
||||||
|
onModalClose
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const selectedEpisodes = items.reduce((acc, item) => {
|
||||||
if (episodeIds.indexOf(item.id) > -1) {
|
if (episodeIds.indexOf(item.id) > -1) {
|
||||||
acc.push(item);
|
acc.push(item);
|
||||||
}
|
}
|
||||||
|
@ -64,12 +69,22 @@ class SelectEpisodeModalContentConnector extends Component {
|
||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
this.props.updateInteractiveImportItem({
|
const episodesPerFile = selectedEpisodes.length / ids.length;
|
||||||
id: this.props.id,
|
const sortedEpisodes = selectedEpisodes.sort((a, b) => {
|
||||||
episodes: _.sortBy(episodes, 'episodeNumber')
|
return a.seasonNumber - b.seasonNumber;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.onModalClose(true);
|
ids.forEach((id, index) => {
|
||||||
|
const startingIndex = index * episodesPerFile;
|
||||||
|
const episodes = sortedEpisodes.slice(startingIndex, startingIndex + episodesPerFile);
|
||||||
|
|
||||||
|
this.props.updateInteractiveImportItem({
|
||||||
|
id,
|
||||||
|
episodes
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
onModalClose(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -87,7 +102,7 @@ class SelectEpisodeModalContentConnector extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
SelectEpisodeModalContentConnector.propTypes = {
|
SelectEpisodeModalContentConnector.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
seriesId: PropTypes.number.isRequired,
|
seriesId: PropTypes.number.isRequired,
|
||||||
seasonNumber: PropTypes.number.isRequired,
|
seasonNumber: PropTypes.number.isRequired,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
|
|
@ -20,6 +20,7 @@ import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
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 SelectEpisodeModal from 'InteractiveImport/Episode/SelectEpisodeModal';
|
||||||
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
|
import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal';
|
||||||
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
||||||
import SelectSeriesModal from 'InteractiveImport/Series/SelectSeriesModal';
|
import SelectSeriesModal from 'InteractiveImport/Series/SelectSeriesModal';
|
||||||
|
@ -90,6 +91,7 @@ const importModeOptions = [
|
||||||
const SELECT = 'select';
|
const SELECT = 'select';
|
||||||
const SERIES = 'series';
|
const SERIES = 'series';
|
||||||
const SEASON = 'season';
|
const SEASON = 'season';
|
||||||
|
const EPISODE = 'episode';
|
||||||
const LANGUAGE = 'language';
|
const LANGUAGE = 'language';
|
||||||
const QUALITY = 'quality';
|
const QUALITY = 'quality';
|
||||||
|
|
||||||
|
@ -208,12 +210,25 @@ class InteractiveImportModalContent extends Component {
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const selectedIds = this.getSelectedIds();
|
const selectedIds = this.getSelectedIds();
|
||||||
const selectedItem = selectedIds.length ? _.find(items, { id: selectedIds[0] }) : null;
|
|
||||||
|
const orderedSelectedIds = items.reduce((acc, file) => {
|
||||||
|
if (selectedIds.includes(file.id)) {
|
||||||
|
acc.push(file.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const selectedItem = selectedIds.length ?
|
||||||
|
items.find((file) => file.id === selectedIds[0]) :
|
||||||
|
null;
|
||||||
|
|
||||||
const errorMessage = getErrorMessage(error, 'Unable to load manual import items');
|
const errorMessage = getErrorMessage(error, 'Unable to load manual import items');
|
||||||
|
|
||||||
const bulkSelectOptions = [
|
const bulkSelectOptions = [
|
||||||
{ key: SELECT, value: 'Select...', disabled: true },
|
{ key: SELECT, value: 'Select...', disabled: true },
|
||||||
{ key: SEASON, value: 'Select Season' },
|
{ key: SEASON, value: 'Select Season' },
|
||||||
|
{ key: EPISODE, value: 'Select Episode(s)' },
|
||||||
{ key: LANGUAGE, value: 'Select Language' },
|
{ key: LANGUAGE, value: 'Select Language' },
|
||||||
{ key: QUALITY, value: 'Select Quality' }
|
{ key: QUALITY, value: 'Select Quality' }
|
||||||
];
|
];
|
||||||
|
@ -374,6 +389,14 @@ class InteractiveImportModalContent extends Component {
|
||||||
onModalClose={this.onSelectModalClose}
|
onModalClose={this.onSelectModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<SelectEpisodeModal
|
||||||
|
isOpen={selectModalOpen === EPISODE}
|
||||||
|
ids={orderedSelectedIds}
|
||||||
|
seriesId={selectedItem && selectedItem.series && selectedItem.series.id}
|
||||||
|
seasonNumber={selectedItem && selectedItem.seasonNumber}
|
||||||
|
onModalClose={this.onSelectModalClose}
|
||||||
|
/>
|
||||||
|
|
||||||
<SelectLanguageModal
|
<SelectLanguageModal
|
||||||
isOpen={selectModalOpen === LANGUAGE}
|
isOpen={selectModalOpen === LANGUAGE}
|
||||||
ids={selectedIds}
|
ids={selectedIds}
|
||||||
|
|
|
@ -337,7 +337,7 @@ class InteractiveImportRow extends Component {
|
||||||
|
|
||||||
<SelectEpisodeModal
|
<SelectEpisodeModal
|
||||||
isOpen={isSelectEpisodeModalOpen}
|
isOpen={isSelectEpisodeModalOpen}
|
||||||
id={id}
|
ids={[id]}
|
||||||
seriesId={series && series.id}
|
seriesId={series && series.id}
|
||||||
seasonNumber={seasonNumber}
|
seasonNumber={seasonNumber}
|
||||||
relativePath={relativePath}
|
relativePath={relativePath}
|
||||||
|
|
Loading…
Reference in New Issue