UI Updates (Cancel Import, Move Artist, Manual Import from Artist)

Ability to cancel an import lookup/search at any point.
Ability to move artist path from Artist Edit or bulk move from Mass Editor.
Trigger manual import for Artist path from Artist Detail page.
Pulled from Sonarr
This commit is contained in:
Qstick
2017-12-29 22:23:04 -05:00
parent 5fae202760
commit d8c89f5bbd
79 changed files with 1075 additions and 376 deletions
@@ -1,3 +1,14 @@
.filterContainer {
display: flex;
justify-content: flex-end;
margin-bottom: 10px;
}
.filterText {
margin-left: 5px;
font-size: $largeFontSize;
}
.footer {
composes: modalFooter from 'Components/Modal/ModalFooter.css';
@@ -4,11 +4,15 @@ import React, { Component } from 'react';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected';
import { icons, kinds } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import Button from 'Components/Link/Button';
import Icon from 'Components/Icon';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import SelectInput from 'Components/Form/SelectInput';
import Menu from 'Components/Menu/Menu';
import MenuButton from 'Components/Menu/MenuButton';
import MenuContent from 'Components/Menu/MenuContent';
import SelectedMenuItem from 'Components/Menu/SelectedMenuItem';
import ModalContent from 'Components/Modal/ModalContent';
import ModalHeader from 'Components/Modal/ModalHeader';
import ModalBody from 'Components/Modal/ModalBody';
@@ -70,6 +74,11 @@ const columns = [
}
];
const filterExistingFilesOptions = {
ALL: 'all',
NEW: 'new'
};
class InteractiveImportModalContent extends Component {
//
@@ -129,6 +138,10 @@ class InteractiveImportModalContent extends Component {
this.props.onImportSelectedPress(selected, this.state.importMode);
}
onFilterExistingFilesChange = (value) => {
this.props.onFilterExistingFilesChange(value !== filterExistingFilesOptions.ALL);
}
onImportModeChange = ({ value }) => {
this.props.onImportModeChange(value);
}
@@ -155,6 +168,8 @@ class InteractiveImportModalContent extends Component {
render() {
const {
downloadId,
showFilterExistingFiles,
filterExistingFiles,
title,
folder,
isFetching,
@@ -205,7 +220,45 @@ class InteractiveImportModalContent extends Component {
}
{
isPopulated && !!items.length &&
isPopulated && showFilterExistingFiles && !isFetching &&
<div className={styles.filterContainer}>
<Menu alignMenu={align.RIGHT}>
<MenuButton>
<Icon
name={icons.FILTER}
size={22}
/>
<div className={styles.filterText}>
{
filterExistingFiles ? 'Unmapped Files Only' : 'All Files'
}
</div>
</MenuButton>
<MenuContent>
<SelectedMenuItem
name={filterExistingFilesOptions.ALL}
isSelected={!filterExistingFiles}
onPress={this.onFilterExistingFilesChange}
>
All Files
</SelectedMenuItem>
<SelectedMenuItem
name={filterExistingFilesOptions.NEW}
isSelected={filterExistingFiles}
onPress={this.onFilterExistingFilesChange}
>
Unmapped Files Only
</SelectedMenuItem>
</MenuContent>
</Menu>
</div>
}
{
isPopulated && !!items.length && !isFetching && !isFetching &&
<Table
columns={columns}
selectAll={true}
@@ -235,7 +288,7 @@ class InteractiveImportModalContent extends Component {
}
{
isPopulated && !items.length &&
isPopulated && !items.length && !isFetching &&
'No audio files were found in the selected folder'
}
</ModalBody>
@@ -303,6 +356,8 @@ class InteractiveImportModalContent extends Component {
InteractiveImportModalContent.propTypes = {
downloadId: PropTypes.string,
showFilterExistingFiles: PropTypes.bool.isRequired,
filterExistingFiles: PropTypes.bool.isRequired,
importMode: PropTypes.string.isRequired,
title: PropTypes.string,
folder: PropTypes.string,
@@ -314,12 +369,14 @@ InteractiveImportModalContent.propTypes = {
sortDirection: PropTypes.string,
interactiveImportErrorMessage: PropTypes.string,
onSortPress: PropTypes.func.isRequired,
onFilterExistingFilesChange: PropTypes.func.isRequired,
onImportModeChange: PropTypes.func.isRequired,
onImportSelectedPress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
InteractiveImportModalContent.defaultProps = {
showFilterExistingFiles: false,
importMode: 'move'
};
@@ -35,7 +35,8 @@ class InteractiveImportModalContentConnector extends Component {
super(props, context);
this.state = {
interactiveImportErrorMessage: null
interactiveImportErrorMessage: null,
filterExistingFiles: true
};
}
@@ -45,7 +46,34 @@ class InteractiveImportModalContentConnector extends Component {
folder
} = this.props;
this.props.fetchInteractiveImportItems({ downloadId, folder });
const {
filterExistingFiles
} = this.state;
this.props.fetchInteractiveImportItems({
downloadId,
folder,
filterExistingFiles
});
}
componentDidUpdate(prevProps, prevState) {
const {
filterExistingFiles
} = this.state;
if (prevState.filterExistingFiles !== filterExistingFiles) {
const {
downloadId,
folder
} = this.props;
this.props.fetchInteractiveImportItems({
downloadId,
folder,
filterExistingFiles
});
}
}
componentWillUnmount() {
@@ -59,6 +87,10 @@ class InteractiveImportModalContentConnector extends Component {
this.props.setInteractiveImportSort({ sortKey, sortDirection });
}
onFilterExistingFilesChange = (filterExistingFiles) => {
this.setState({ filterExistingFiles });
}
onImportModeChange = (importMode) => {
this.props.setInteractiveImportMode({ importMode });
}
@@ -122,11 +154,18 @@ class InteractiveImportModalContentConnector extends Component {
// Render
render() {
const {
interactiveImportErrorMessage,
filterExistingFiles
} = this.state;
return (
<InteractiveImportModalContent
{...this.props}
interactiveImportErrorMessage={this.state.interactiveImportErrorMessage}
interactiveImportErrorMessage={interactiveImportErrorMessage}
filterExistingFiles={filterExistingFiles}
onSortPress={this.onSortPress}
onFilterExistingFilesChange={this.onFilterExistingFilesChange}
onImportModeChange={this.onImportModeChange}
onImportSelectedPress={this.onImportSelectedPress}
/>
@@ -137,6 +176,7 @@ class InteractiveImportModalContentConnector extends Component {
InteractiveImportModalContentConnector.propTypes = {
downloadId: PropTypes.string,
folder: PropTypes.string,
filterExistingFiles: PropTypes.bool.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
fetchInteractiveImportItems: PropTypes.func.isRequired,
setInteractiveImportSort: PropTypes.func.isRequired,
@@ -146,6 +186,10 @@ InteractiveImportModalContentConnector.propTypes = {
onModalClose: PropTypes.func.isRequired
};
InteractiveImportModalContentConnector.defaultProps = {
filterExistingFiles: true
};
export default connectSection(
createMapStateToProps,
mapDispatchToProps,
@@ -15,6 +15,12 @@ import TableBody from 'Components/Table/TableBody';
import SelectTrackRow from './SelectTrackRow';
const columns = [
{
name: 'mediumNumber',
label: 'Medium',
isSortable: true,
isVisible: true
},
{
name: 'trackNumber',
label: '#',
@@ -127,7 +133,8 @@ class SelectTrackModalContent extends Component {
<SelectTrackRow
key={item.id}
id={item.id}
trackNumber={item.trackNumber}
mediumNumber={item.mediumNumber}
trackNumber={item.absoluteTrackNumber}
title={item.title}
isSelected={selectedState[item.id]}
onSelectedChange={this.onSelectedChange}
@@ -24,6 +24,7 @@ class SelectTrackRow extends Component {
render() {
const {
id,
mediumNumber,
trackNumber,
title,
isSelected,
@@ -38,6 +39,10 @@ class SelectTrackRow extends Component {
onSelectedChange={onSelectedChange}
/>
<TableRowCell>
{mediumNumber}
</TableRowCell>
<TableRowCell>
{trackNumber}
</TableRowCell>
@@ -53,6 +58,7 @@ class SelectTrackRow extends Component {
SelectTrackRow.propTypes = {
id: PropTypes.number.isRequired,
mediumNumber: PropTypes.number.isRequired,
trackNumber: PropTypes.number.isRequired,
title: PropTypes.string.isRequired,
isSelected: PropTypes.bool,