From 11164ab838c9a51a4b88eb56aa1d0349f788c7c4 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sat, 23 Feb 2019 11:12:20 -0800 Subject: [PATCH] New: Bulk select language and quality in Manual Import --- .../History/Details/HistoryDetails.css | 2 +- .../InteractiveImportModalContent.css | 16 +-- .../InteractiveImportModalContent.js | 99 ++++++++++++------- .../Interactive/InteractiveImportRow.js | 4 +- .../SelectLanguageModalContentConnector.js | 18 ++-- .../SelectQualityModalContentConnector.js | 18 ++-- .../Store/Actions/interactiveImportActions.js | 19 ++++ 7 files changed, 106 insertions(+), 70 deletions(-) diff --git a/frontend/src/Activity/History/Details/HistoryDetails.css b/frontend/src/Activity/History/Details/HistoryDetails.css index 03f8fd3ce..98c16a3a5 100644 --- a/frontend/src/Activity/History/Details/HistoryDetails.css +++ b/frontend/src/Activity/History/Details/HistoryDetails.css @@ -1,5 +1,5 @@ .description { - composes: title from 'Components/DescriptionList/DescriptionListItemDescription.css'; + composes: description from 'Components/DescriptionList/DescriptionListItemDescription.css'; overflow-wrap: break-word; } diff --git a/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.css b/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.css index 5bad6c050..0ca849063 100644 --- a/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.css +++ b/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.css @@ -16,24 +16,21 @@ } .leftButtons, -.centerButtons, .rightButtons { display: flex; - flex: 1 0 33%; + flex: 1 0 50%; flex-wrap: wrap; } -.centerButtons { - justify-content: center; -} - .rightButtons { justify-content: flex-end; } -.importMode { +.importMode, +.bulkSelect { composes: select from 'Components/Form/SelectInput.css'; + margin-right: 10px; width: auto; } @@ -44,7 +41,6 @@ @media only screen and (max-width: $breakpointSmall) { .footer { .leftButtons, - .centerButtons, .rightButtons { flex-direction: column; } @@ -53,10 +49,6 @@ align-items: flex-start; } - .centerButtons { - align-items: center; - } - .rightButtons { align-items: flex-end; } diff --git a/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.js b/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.js index f0eaf0965..a853e845c 100644 --- a/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.js +++ b/frontend/src/InteractiveImport/Interactive/InteractiveImportModalContent.js @@ -20,6 +20,8 @@ import ModalBody from 'Components/Modal/ModalBody'; import ModalFooter from 'Components/Modal/ModalFooter'; import Table from 'Components/Table/Table'; import TableBody from 'Components/Table/TableBody'; +import SelectLanguageModal from 'InteractiveImport/Language/SelectLanguageModal'; +import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal'; import SelectSeriesModal from 'InteractiveImport/Series/SelectSeriesModal'; import SelectSeasonModal from 'InteractiveImport/Season/SelectSeasonModal'; import InteractiveImportRow from './InteractiveImportRow'; @@ -80,6 +82,17 @@ const filterExistingFilesOptions = { NEW: 'new' }; +const importModeOptions = [ + { key: 'move', value: 'Move Files' }, + { key: 'copy', value: 'Copy Files' } +]; + +const SELECT = 'select'; +const SERIES = 'series'; +const SEASON = 'season'; +const LANGUAGE = 'language'; +const QUALITY = 'quality'; + class InteractiveImportModalContent extends Component { // @@ -94,8 +107,7 @@ class InteractiveImportModalContent extends Component { lastToggled: null, selectedState: {}, invalidRowsSelected: [], - isSelectSeriesModalOpen: false, - isSelectSeasonModalOpen: false + selectModalOpen: null }; } @@ -155,20 +167,12 @@ class InteractiveImportModalContent extends Component { this.props.onImportModeChange(value); } - onSelectSeriesPress = () => { - this.setState({ isSelectSeriesModalOpen: true }); + onSelectModalSelect = ({ value }) => { + this.setState({ selectModalOpen: value }); } - onSelectSeasonPress = () => { - this.setState({ isSelectSeasonModalOpen: true }); - } - - onSelectSeriesModalClose = () => { - this.setState({ isSelectSeriesModalOpen: false }); - } - - onSelectSeasonModalClose = () => { - this.setState({ isSelectSeasonModalOpen: false }); + onSelectModalClose = () => { + this.setState({ selectModalOpen: null }); } // @@ -200,19 +204,27 @@ class InteractiveImportModalContent extends Component { allUnselected, selectedState, invalidRowsSelected, - isSelectSeriesModalOpen, - isSelectSeasonModalOpen + selectModalOpen } = this.state; const selectedIds = this.getSelectedIds(); const selectedItem = selectedIds.length ? _.find(items, { id: selectedIds[0] }) : null; const errorMessage = getErrorMessage(error, 'Unable to load manual import items'); - const importModeOptions = [ - { key: 'move', value: 'Move Files' }, - { key: 'copy', value: 'Copy Files' } + const bulkSelectOptions = [ + { key: SELECT, value: 'Select...', disabled: true }, + { key: SEASON, value: 'Select Season' }, + { key: LANGUAGE, value: 'Select Language' }, + { key: QUALITY, value: 'Select Qualty' } ]; + if (allowSeriesChange) { + bulkSelectOptions.splice(1, 0, { + key: SERIES, + value: 'Select Series' + }); + } + return ( @@ -308,28 +320,25 @@ class InteractiveImportModalContent extends Component {
{ - !downloadId && showImportMode && + !downloadId && showImportMode ? - } -
- -
- { - allowSeriesChange && - + /> : + null } - +
@@ -353,16 +362,32 @@ class InteractiveImportModalContent extends Component { + + + + ); diff --git a/frontend/src/InteractiveImport/Interactive/InteractiveImportRow.js b/frontend/src/InteractiveImport/Interactive/InteractiveImportRow.js index d95af5d72..eca8d4fc8 100644 --- a/frontend/src/InteractiveImport/Interactive/InteractiveImportRow.js +++ b/frontend/src/InteractiveImport/Interactive/InteractiveImportRow.js @@ -328,7 +328,7 @@ class InteractiveImportRow extends Component { 1 : false} real={quality ? quality.revision.real > 0 : false} @@ -337,7 +337,7 @@ class InteractiveImportRow extends Component { diff --git a/frontend/src/InteractiveImport/Language/SelectLanguageModalContentConnector.js b/frontend/src/InteractiveImport/Language/SelectLanguageModalContentConnector.js index 56e95b861..c084d4915 100644 --- a/frontend/src/InteractiveImport/Language/SelectLanguageModalContentConnector.js +++ b/frontend/src/InteractiveImport/Language/SelectLanguageModalContentConnector.js @@ -4,7 +4,7 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { fetchLanguageProfileSchema } from 'Store/Actions/settingsActions'; -import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions'; +import { updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions'; import SelectLanguageModalContent from './SelectLanguageModalContent'; function createMapStateToProps() { @@ -29,8 +29,8 @@ function createMapStateToProps() { } const mapDispatchToProps = { - fetchLanguageProfileSchema, - updateInteractiveImportItem + dispatchFetchLanguageProfileSchema: fetchLanguageProfileSchema, + dispatchUpdateInteractiveImportItems: updateInteractiveImportItems }; class SelectLanguageModalContentConnector extends Component { @@ -40,7 +40,7 @@ class SelectLanguageModalContentConnector extends Component { componentDidMount = () => { if (!this.props.isPopulated) { - this.props.fetchLanguageProfileSchema(); + this.props.dispatchFetchLanguageProfileSchema(); } } @@ -52,8 +52,8 @@ class SelectLanguageModalContentConnector extends Component { const language = _.find(this.props.items, (item) => item.language.id === languageId).language; - this.props.updateInteractiveImportItem({ - id: this.props.id, + this.props.dispatchUpdateInteractiveImportItems({ + ids: this.props.ids, language }); @@ -74,13 +74,13 @@ class SelectLanguageModalContentConnector extends Component { } SelectLanguageModalContentConnector.propTypes = { - id: PropTypes.number.isRequired, + ids: PropTypes.arrayOf(PropTypes.number).isRequired, isFetching: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired, error: PropTypes.object, items: PropTypes.arrayOf(PropTypes.object).isRequired, - fetchLanguageProfileSchema: PropTypes.func.isRequired, - updateInteractiveImportItem: PropTypes.func.isRequired, + dispatchFetchLanguageProfileSchema: PropTypes.func.isRequired, + dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired }; diff --git a/frontend/src/InteractiveImport/Quality/SelectQualityModalContentConnector.js b/frontend/src/InteractiveImport/Quality/SelectQualityModalContentConnector.js index 20a49c768..1cf55cde6 100644 --- a/frontend/src/InteractiveImport/Quality/SelectQualityModalContentConnector.js +++ b/frontend/src/InteractiveImport/Quality/SelectQualityModalContentConnector.js @@ -5,7 +5,7 @@ import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import getQualities from 'Utilities/Quality/getQualities'; import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions'; -import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions'; +import { updateInteractiveImportItems } from 'Store/Actions/interactiveImportActions'; import SelectQualityModalContent from './SelectQualityModalContent'; function createMapStateToProps() { @@ -30,8 +30,8 @@ function createMapStateToProps() { } const mapDispatchToProps = { - fetchQualityProfileSchema, - updateInteractiveImportItem + dispatchFetchQualityProfileSchema: fetchQualityProfileSchema, + dispatchUpdateInteractiveImportItems: updateInteractiveImportItems }; class SelectQualityModalContentConnector extends Component { @@ -41,7 +41,7 @@ class SelectQualityModalContentConnector extends Component { componentDidMount = () => { if (!this.props.isPopulated) { - this.props.fetchQualityProfileSchema(); + this.props.dispatchFetchQualityProfileSchema(); } } @@ -57,8 +57,8 @@ class SelectQualityModalContentConnector extends Component { real: real ? 1 : 0 }; - this.props.updateInteractiveImportItem({ - id: this.props.id, + this.props.dispatchUpdateInteractiveImportItems({ + ids: this.props.ids, quality: { quality, revision @@ -82,13 +82,13 @@ class SelectQualityModalContentConnector extends Component { } SelectQualityModalContentConnector.propTypes = { - id: PropTypes.number.isRequired, + ids: PropTypes.arrayOf(PropTypes.number).isRequired, isFetching: PropTypes.bool.isRequired, isPopulated: PropTypes.bool.isRequired, error: PropTypes.object, items: PropTypes.arrayOf(PropTypes.object).isRequired, - fetchQualityProfileSchema: PropTypes.func.isRequired, - updateInteractiveImportItem: PropTypes.func.isRequired, + dispatchFetchQualityProfileSchema: PropTypes.func.isRequired, + dispatchUpdateInteractiveImportItems: PropTypes.func.isRequired, onModalClose: PropTypes.func.isRequired }; diff --git a/frontend/src/Store/Actions/interactiveImportActions.js b/frontend/src/Store/Actions/interactiveImportActions.js index 9dd003d3f..faf0744eb 100644 --- a/frontend/src/Store/Actions/interactiveImportActions.js +++ b/frontend/src/Store/Actions/interactiveImportActions.js @@ -68,6 +68,7 @@ export const persistState = [ export const FETCH_INTERACTIVE_IMPORT_ITEMS = 'interactiveImport/fetchInteractiveImportItems'; export const SET_INTERACTIVE_IMPORT_SORT = 'interactiveImport/setInteractiveImportSort'; export const UPDATE_INTERACTIVE_IMPORT_ITEM = 'interactiveImport/updateInteractiveImportItem'; +export const UPDATE_INTERACTIVE_IMPORT_ITEMS = 'interactiveImport/updateInteractiveImportItems'; export const CLEAR_INTERACTIVE_IMPORT = 'interactiveImport/clearInteractiveImport'; export const ADD_RECENT_FOLDER = 'interactiveImport/addRecentFolder'; export const REMOVE_RECENT_FOLDER = 'interactiveImport/removeRecentFolder'; @@ -83,6 +84,7 @@ export const CLEAR_INTERACTIVE_IMPORT_EPISODES = 'interactiveImport/clearInterac export const fetchInteractiveImportItems = createThunk(FETCH_INTERACTIVE_IMPORT_ITEMS); export const setInteractiveImportSort = createAction(SET_INTERACTIVE_IMPORT_SORT); export const updateInteractiveImportItem = createAction(UPDATE_INTERACTIVE_IMPORT_ITEM); +export const updateInteractiveImportItems = createAction(UPDATE_INTERACTIVE_IMPORT_ITEMS); export const clearInteractiveImport = createAction(CLEAR_INTERACTIVE_IMPORT); export const addRecentFolder = createAction(ADD_RECENT_FOLDER); export const removeRecentFolder = createAction(REMOVE_RECENT_FOLDER); @@ -152,6 +154,23 @@ export const reducers = createHandleActions({ return newState; }, + [UPDATE_INTERACTIVE_IMPORT_ITEMS]: (state, { payload }) => { + const ids = payload.ids; + const newState = Object.assign({}, state); + const items = [...newState.items]; + + ids.forEach((id) => { + const index = items.findIndex((item) => item.id === id); + const item = Object.assign({}, items[index], payload); + + items.splice(index, 1, item); + }); + + newState.items = items; + + return newState; + }, + [ADD_RECENT_FOLDER]: function(state, { payload }) { const folder = payload.folder; const recentFolder = { folder, lastUsed: moment().toISOString() };