mirror of
https://github.com/lidarr/lidarr.git
synced 2025-08-19 13:10:13 -07:00
[UI Work] Interactive Import, More Artist Detail
This commit is contained in:
parent
0054226307
commit
f05332cf6e
42 changed files with 486 additions and 549 deletions
|
@ -1,9 +1,9 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import SelectSeasonModalContentConnector from './SelectSeasonModalContentConnector';
|
||||
import SelectAlbumModalContentConnector from './SelectAlbumModalContentConnector';
|
||||
|
||||
class SelectSeasonModal extends Component {
|
||||
class SelectAlbumModal extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
@ -20,7 +20,7 @@ class SelectSeasonModal extends Component {
|
|||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<SelectSeasonModalContentConnector
|
||||
<SelectAlbumModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
|
@ -29,9 +29,9 @@ class SelectSeasonModal extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
SelectSeasonModal.propTypes = {
|
||||
SelectAlbumModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectSeasonModal;
|
||||
export default SelectAlbumModal;
|
|
@ -5,9 +5,9 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import SelectSeasonRow from './SelectSeasonRow';
|
||||
import SelectAlbumRow from './SelectAlbumRow';
|
||||
|
||||
class SelectSeasonModalContent extends Component {
|
||||
class SelectAlbumModalContent extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
@ -15,24 +15,25 @@ class SelectSeasonModalContent extends Component {
|
|||
render() {
|
||||
const {
|
||||
items,
|
||||
onSeasonSelect,
|
||||
onAlbumSelect,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Manual Import - Select Season
|
||||
Manual Import - Select Album
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<SelectSeasonRow
|
||||
key={item.seasonNumber}
|
||||
seasonNumber={item.seasonNumber}
|
||||
onSeasonSelect={onSeasonSelect}
|
||||
<SelectAlbumRow
|
||||
key={item.id}
|
||||
id={item.id}
|
||||
title={item.title}
|
||||
onAlbumSelect={onAlbumSelect}
|
||||
/>
|
||||
);
|
||||
})
|
||||
|
@ -49,10 +50,10 @@ class SelectSeasonModalContent extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
SelectSeasonModalContent.propTypes = {
|
||||
SelectAlbumModalContent.propTypes = {
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onSeasonSelect: PropTypes.func.isRequired,
|
||||
onAlbumSelect: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectSeasonModalContent;
|
||||
export default SelectAlbumModalContent;
|
|
@ -1,17 +1,18 @@
|
|||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
|
||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
||||
import SelectSeasonModalContent from './SelectSeasonModalContent';
|
||||
import SelectAlbumModalContent from './SelectAlbumModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createArtistSelector(),
|
||||
(series) => {
|
||||
return {
|
||||
items: series.seasons
|
||||
items: series.albums
|
||||
};
|
||||
}
|
||||
);
|
||||
|
@ -21,16 +22,18 @@ const mapDispatchToProps = {
|
|||
updateInteractiveImportItem
|
||||
};
|
||||
|
||||
class SelectSeasonModalContentConnector extends Component {
|
||||
class SelectAlbumModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onSeasonSelect = (seasonNumber) => {
|
||||
onAlbumSelect = (albumId) => {
|
||||
const album = _.find(this.props.items, { id: albumId });
|
||||
|
||||
this.props.ids.forEach((id) => {
|
||||
this.props.updateInteractiveImportItem({
|
||||
id,
|
||||
seasonNumber,
|
||||
album,
|
||||
episodes: []
|
||||
});
|
||||
});
|
||||
|
@ -43,15 +46,15 @@ class SelectSeasonModalContentConnector extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<SelectSeasonModalContent
|
||||
<SelectAlbumModalContent
|
||||
{...this.props}
|
||||
onSeasonSelect={this.onSeasonSelect}
|
||||
onAlbumSelect={this.onAlbumSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectSeasonModalContentConnector.propTypes = {
|
||||
SelectAlbumModalContentConnector.propTypes = {
|
||||
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
artistId: PropTypes.number.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
|
@ -59,4 +62,4 @@ SelectSeasonModalContentConnector.propTypes = {
|
|||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(SelectSeasonModalContentConnector);
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(SelectAlbumModalContentConnector);
|
37
frontend/src/InteractiveImport/Album/SelectAlbumRow.js
Normal file
37
frontend/src/InteractiveImport/Album/SelectAlbumRow.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import styles from './SelectAlbumRow.css';
|
||||
|
||||
class SelectAlbumRow extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onPress = () => {
|
||||
this.props.onAlbumSelect(this.props.id);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Link
|
||||
className={styles.season}
|
||||
component="div"
|
||||
onPress={this.onPress}
|
||||
>
|
||||
{this.props.title}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectAlbumRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
onAlbumSelect: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectAlbumRow;
|
|
@ -37,7 +37,7 @@ class SelectArtistModalContent extends Component {
|
|||
render() {
|
||||
const {
|
||||
items,
|
||||
onSeriesSelect,
|
||||
onArtistSelect,
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
|
@ -46,7 +46,7 @@ class SelectArtistModalContent extends Component {
|
|||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Manual Import - Select Series
|
||||
Manual Import - Select Artist
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody
|
||||
|
@ -55,7 +55,7 @@ class SelectArtistModalContent extends Component {
|
|||
>
|
||||
<TextInput
|
||||
className={styles.filterInput}
|
||||
placeholder="Filter series"
|
||||
placeholder="Filter artist"
|
||||
name="filter"
|
||||
value={filter}
|
||||
autoFocus={true}
|
||||
|
@ -65,13 +65,13 @@ class SelectArtistModalContent extends Component {
|
|||
<Scroller className={styles.scroller}>
|
||||
{
|
||||
items.map((item) => {
|
||||
return item.title.toLowerCase().includes(filter) ?
|
||||
return item.artistName.toLowerCase().includes(filter) ?
|
||||
(
|
||||
<SelectArtistRow
|
||||
key={item.id}
|
||||
id={item.id}
|
||||
title={item.title}
|
||||
onSeriesSelect={onSeriesSelect}
|
||||
artistName={item.artistName}
|
||||
onArtistSelect={onArtistSelect}
|
||||
/>
|
||||
) :
|
||||
null;
|
||||
|
@ -92,7 +92,7 @@ class SelectArtistModalContent extends Component {
|
|||
|
||||
SelectArtistModalContent.propTypes = {
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onSeriesSelect: PropTypes.func.isRequired,
|
||||
onArtistSelect: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
|
@ -27,15 +27,15 @@ class SelectArtistModalContentConnector extends Component {
|
|||
//
|
||||
// Listeners
|
||||
|
||||
onSeriesSelect = (artistId) => {
|
||||
const series = _.find(this.props.items, { id: artistId });
|
||||
onArtistSelect = (artistId) => {
|
||||
const artist = _.find(this.props.items, { id: artistId });
|
||||
|
||||
this.props.ids.forEach((id) => {
|
||||
this.props.updateInteractiveImportItem({
|
||||
id,
|
||||
series,
|
||||
seasonNumber: undefined,
|
||||
episodes: []
|
||||
artist,
|
||||
album: undefined,
|
||||
tracks: []
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -49,7 +49,7 @@ class SelectArtistModalContentConnector extends Component {
|
|||
return (
|
||||
<SelectArtistModalContent
|
||||
{...this.props}
|
||||
onSeriesSelect={this.onSeriesSelect}
|
||||
onArtistSelect={this.onArtistSelect}
|
||||
/>
|
||||
);
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
.series {
|
||||
.artist {
|
||||
padding: 8px;
|
||||
border-bottom: 1px solid $borderColor;
|
||||
}
|
|
@ -9,7 +9,7 @@ class SelectArtistRow extends Component {
|
|||
// Listeners
|
||||
|
||||
onPress = () => {
|
||||
this.props.onSeriesSelect(this.props.id);
|
||||
this.props.onArtistSelect(this.props.id);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -18,11 +18,11 @@ class SelectArtistRow extends Component {
|
|||
render() {
|
||||
return (
|
||||
<Link
|
||||
className={styles.series}
|
||||
className={styles.artist}
|
||||
component="div"
|
||||
onPress={this.onPress}
|
||||
>
|
||||
{this.props.title}
|
||||
{this.props.artistName}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ class SelectArtistRow extends Component {
|
|||
|
||||
SelectArtistRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
onSeriesSelect: PropTypes.func.isRequired
|
||||
artistName: PropTypes.string.isRequired,
|
||||
onArtistSelect: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectArtistRow;
|
|
@ -15,8 +15,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 SelectArtistModal from 'InteractiveImport/Series/SelectArtistModal';
|
||||
import SelectSeasonModal from 'InteractiveImport/Season/SelectSeasonModal';
|
||||
import SelectArtistModal from 'InteractiveImport/Artist/SelectArtistModal';
|
||||
import SelectAlbumModal from 'InteractiveImport/Album/SelectAlbumModal';
|
||||
import InteractiveImportRow from './InteractiveImportRow';
|
||||
import styles from './InteractiveImportModalContent.css';
|
||||
|
||||
|
@ -28,19 +28,19 @@ const columns = [
|
|||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'series',
|
||||
label: 'Series',
|
||||
name: 'artist',
|
||||
label: 'Artist',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'season',
|
||||
label: 'Season',
|
||||
name: 'album',
|
||||
label: 'Album',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'episodes',
|
||||
label: 'Episode(s)',
|
||||
name: 'tracks',
|
||||
label: 'Track(s)',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
|
@ -79,7 +79,7 @@ class InteractiveImportModalContent extends Component {
|
|||
selectedState: {},
|
||||
invalidRowsSelected: [],
|
||||
isSelectArtistModalOpen: false,
|
||||
isSelectSeasonModalOpen: false
|
||||
isSelectAlbumModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -131,16 +131,16 @@ class InteractiveImportModalContent extends Component {
|
|||
this.setState({ isSelectArtistModalOpen: true });
|
||||
}
|
||||
|
||||
onSelectSeasonPress = () => {
|
||||
this.setState({ isSelectSeasonModalOpen: true });
|
||||
onSelectAlbumPress = () => {
|
||||
this.setState({ isSelectAlbumModalOpen: true });
|
||||
}
|
||||
|
||||
onSelectArtistModalClose = () => {
|
||||
this.setState({ isSelectArtistModalOpen: false });
|
||||
}
|
||||
|
||||
onSelectSeasonModalClose = () => {
|
||||
this.setState({ isSelectSeasonModalOpen: false });
|
||||
onSelectAlbumModalClose = () => {
|
||||
this.setState({ isSelectAlbumModalOpen: false });
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -169,7 +169,7 @@ class InteractiveImportModalContent extends Component {
|
|||
selectedState,
|
||||
invalidRowsSelected,
|
||||
isSelectArtistModalOpen,
|
||||
isSelectSeasonModalOpen
|
||||
isSelectAlbumModalOpen
|
||||
} = this.state;
|
||||
|
||||
const selectedIds = this.getSelectedIds();
|
||||
|
@ -250,11 +250,11 @@ class InteractiveImportModalContent extends Component {
|
|||
|
||||
<div className={downloadId ? styles.leftButtons : styles.centerButtons}>
|
||||
<Button onPress={this.onSelectArtistPress}>
|
||||
Select Series
|
||||
Select Artist
|
||||
</Button>
|
||||
|
||||
<Button onPress={this.onSelectSeasonPress}>
|
||||
Select Season
|
||||
<Button onPress={this.onSelectAlbumPress}>
|
||||
Select Album
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
@ -284,11 +284,11 @@ class InteractiveImportModalContent extends Component {
|
|||
onModalClose={this.onSelectArtistModalClose}
|
||||
/>
|
||||
|
||||
<SelectSeasonModal
|
||||
isOpen={isSelectSeasonModalOpen}
|
||||
<SelectAlbumModal
|
||||
isOpen={isSelectAlbumModalOpen}
|
||||
ids={selectedIds}
|
||||
artistId={selectedItem && selectedItem.series && selectedItem.series.id}
|
||||
onModalClose={this.onSelectSeasonModalClose}
|
||||
onModalClose={this.onSelectAlbumModalClose}
|
||||
/>
|
||||
</ModalContent>
|
||||
);
|
||||
|
|
|
@ -71,31 +71,32 @@ class InteractiveImportModalContentConnector extends Component {
|
|||
|
||||
if (isSelected) {
|
||||
const {
|
||||
series,
|
||||
seasonNumber,
|
||||
episodes,
|
||||
artist,
|
||||
album,
|
||||
tracks,
|
||||
quality
|
||||
} = item;
|
||||
|
||||
if (!series) {
|
||||
this.setState({ interactiveImportErrorMessage: 'Series must be chosen for each selected file' });
|
||||
if (!artist) {
|
||||
this.setState({ interactiveImportErrorMessage: 'Artist must be chosen for each selected file' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isNaN(seasonNumber)) {
|
||||
this.setState({ interactiveImportErrorMessage: 'Season must be chosen for each selected file' });
|
||||
if (!album) {
|
||||
this.setState({ interactiveImportErrorMessage: 'Album must be chosen for each selected file' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!episodes || !episodes.length) {
|
||||
this.setState({ interactiveImportErrorMessage: 'One or more episodes must be chosen for each selected file' });
|
||||
if (!tracks || !tracks.length) {
|
||||
this.setState({ interactiveImportErrorMessage: 'One or more tracks must be chosen for each selected file' });
|
||||
return false;
|
||||
}
|
||||
|
||||
files.push({
|
||||
path: item.path,
|
||||
artistId: series.id,
|
||||
episodeIds: _.map(episodes, 'id'),
|
||||
artistId: artist.id,
|
||||
albumId: album.id,
|
||||
trackIds: _.map(tracks, 'id'),
|
||||
quality,
|
||||
downloadId: this.props.downloadId
|
||||
});
|
||||
|
|
|
@ -9,9 +9,9 @@ import TableRowCellButton from 'Components/Table/Cells/TableRowCellButton';
|
|||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import EpisodeQuality from 'Episode/EpisodeQuality';
|
||||
import SelectArtistModal from 'InteractiveImport/Series/SelectArtistModal';
|
||||
import SelectSeasonModal from 'InteractiveImport/Season/SelectSeasonModal';
|
||||
import SelectEpisodeModal from 'InteractiveImport/Episode/SelectEpisodeModal';
|
||||
import SelectArtistModal from 'InteractiveImport/Artist/SelectArtistModal';
|
||||
import SelectAlbumModal from 'InteractiveImport/Album/SelectAlbumModal';
|
||||
import SelectTrackModal from 'InteractiveImport/Track/SelectTrackModal';
|
||||
import SelectQualityModal from 'InteractiveImport/Quality/SelectQualityModal';
|
||||
import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder';
|
||||
import styles from './InteractiveImportRow.css';
|
||||
|
@ -26,8 +26,8 @@ class InteractiveImportRow extends Component {
|
|||
|
||||
this.state = {
|
||||
isSelectArtistModalOpen: false,
|
||||
isSelectSeasonModalOpen: false,
|
||||
isSelectEpisodeModalOpen: false,
|
||||
isSelectAlbumModalOpen: false,
|
||||
isSelectTrackModalOpen: false,
|
||||
isSelectQualityModalOpen: false
|
||||
};
|
||||
}
|
||||
|
@ -35,13 +35,13 @@ class InteractiveImportRow extends Component {
|
|||
componentDidMount() {
|
||||
const {
|
||||
id,
|
||||
series,
|
||||
seasonNumber,
|
||||
episodes,
|
||||
artist,
|
||||
album,
|
||||
tracks,
|
||||
quality
|
||||
} = this.props;
|
||||
|
||||
if (series && seasonNumber !== undefined && episodes.length && quality) {
|
||||
if (artist && album !== undefined && tracks.length && quality) {
|
||||
this.props.onSelectedChange({ id, value: true });
|
||||
}
|
||||
}
|
||||
|
@ -49,9 +49,9 @@ class InteractiveImportRow extends Component {
|
|||
componentDidUpdate(prevProps) {
|
||||
const {
|
||||
id,
|
||||
series,
|
||||
seasonNumber,
|
||||
episodes,
|
||||
artist,
|
||||
album,
|
||||
tracks,
|
||||
quality,
|
||||
isSelected,
|
||||
onValidRowChange
|
||||
|
@ -61,7 +61,7 @@ class InteractiveImportRow extends Component {
|
|||
return;
|
||||
}
|
||||
|
||||
const isValid = !!(series && seasonNumber != null && episodes.length && quality);
|
||||
const isValid = !!(artist && album != null && tracks.length && quality);
|
||||
|
||||
if (isSelected && !isValid) {
|
||||
onValidRowChange(id, false);
|
||||
|
@ -91,12 +91,12 @@ class InteractiveImportRow extends Component {
|
|||
this.setState({ isSelectArtistModalOpen: true });
|
||||
}
|
||||
|
||||
onSelectSeasonPress = () => {
|
||||
this.setState({ isSelectSeasonModalOpen: true });
|
||||
onSelectAlbumPress = () => {
|
||||
this.setState({ isSelectAlbumModalOpen: true });
|
||||
}
|
||||
|
||||
onSelectEpisodePress = () => {
|
||||
this.setState({ isSelectEpisodeModalOpen: true });
|
||||
onSelectTrackPress = () => {
|
||||
this.setState({ isSelectTrackModalOpen: true });
|
||||
}
|
||||
|
||||
onSelectQualityPress = () => {
|
||||
|
@ -108,13 +108,13 @@ class InteractiveImportRow extends Component {
|
|||
this.selectRowAfterChange(changed);
|
||||
}
|
||||
|
||||
onSelectSeasonModalClose = (changed) => {
|
||||
this.setState({ isSelectSeasonModalOpen: false });
|
||||
onSelectAlbumModalClose = (changed) => {
|
||||
this.setState({ isSelectAlbumModalOpen: false });
|
||||
this.selectRowAfterChange(changed);
|
||||
}
|
||||
|
||||
onSelectEpisodeModalClose = (changed) => {
|
||||
this.setState({ isSelectEpisodeModalOpen: false });
|
||||
onSelectTrackModalClose = (changed) => {
|
||||
this.setState({ isSelectTrackModalOpen: false });
|
||||
this.selectRowAfterChange(changed);
|
||||
}
|
||||
|
||||
|
@ -130,9 +130,9 @@ class InteractiveImportRow extends Component {
|
|||
const {
|
||||
id,
|
||||
relativePath,
|
||||
series,
|
||||
seasonNumber,
|
||||
episodes,
|
||||
artist,
|
||||
album,
|
||||
tracks,
|
||||
quality,
|
||||
size,
|
||||
rejections,
|
||||
|
@ -142,18 +142,19 @@ class InteractiveImportRow extends Component {
|
|||
|
||||
const {
|
||||
isSelectArtistModalOpen,
|
||||
isSelectSeasonModalOpen,
|
||||
isSelectEpisodeModalOpen,
|
||||
isSelectAlbumModalOpen,
|
||||
isSelectTrackModalOpen,
|
||||
isSelectQualityModalOpen
|
||||
} = this.state;
|
||||
|
||||
const seriesTitle = series ? series.title : '';
|
||||
const episodeNumbers = episodes.map((episode) => episode.episodeNumber)
|
||||
const seriesTitle = artist ? artist.artistName : '';
|
||||
const albumTitle = album ? album.title : '';
|
||||
const trackNumbers = tracks.map((episode) => episode.trackNumber)
|
||||
.join(', ');
|
||||
|
||||
const showSeriesPlaceholder = isSelected && !series;
|
||||
const showSeasonNumberPlaceholder = isSelected && !!series && isNaN(seasonNumber);
|
||||
const showEpisodeNumbersPlaceholder = isSelected && Number.isInteger(seasonNumber) && !episodes.length;
|
||||
const showSeriesPlaceholder = isSelected && !artist;
|
||||
const showSeasonNumberPlaceholder = isSelected && !!artist && !album;
|
||||
const showEpisodeNumbersPlaceholder = isSelected && !!album && !tracks.length;
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
|
@ -179,20 +180,20 @@ class InteractiveImportRow extends Component {
|
|||
</TableRowCellButton>
|
||||
|
||||
<TableRowCellButton
|
||||
isDisabled={!series}
|
||||
onPress={this.onSelectSeasonPress}
|
||||
isDisabled={!artist}
|
||||
onPress={this.onSelectAlbumPress}
|
||||
>
|
||||
{
|
||||
showSeasonNumberPlaceholder ? <InteractiveImportRowCellPlaceholder /> : seasonNumber
|
||||
showSeasonNumberPlaceholder ? <InteractiveImportRowCellPlaceholder /> : albumTitle
|
||||
}
|
||||
</TableRowCellButton>
|
||||
|
||||
<TableRowCellButton
|
||||
isDisabled={!series || isNaN(seasonNumber)}
|
||||
onPress={this.onSelectEpisodePress}
|
||||
isDisabled={!artist || !album}
|
||||
onPress={this.onSelectTrackPress}
|
||||
>
|
||||
{
|
||||
showEpisodeNumbersPlaceholder ? <InteractiveImportRowCellPlaceholder /> : episodeNumbers
|
||||
showEpisodeNumbersPlaceholder ? <InteractiveImportRowCellPlaceholder /> : trackNumbers
|
||||
}
|
||||
</TableRowCellButton>
|
||||
|
||||
|
@ -244,19 +245,19 @@ class InteractiveImportRow extends Component {
|
|||
onModalClose={this.onSelectArtistModalClose}
|
||||
/>
|
||||
|
||||
<SelectSeasonModal
|
||||
isOpen={isSelectSeasonModalOpen}
|
||||
<SelectAlbumModal
|
||||
isOpen={isSelectAlbumModalOpen}
|
||||
ids={[id]}
|
||||
artistId={series && series.id}
|
||||
onModalClose={this.onSelectSeasonModalClose}
|
||||
artistId={artist && artist.id}
|
||||
onModalClose={this.onSelectAlbumModalClose}
|
||||
/>
|
||||
|
||||
<SelectEpisodeModal
|
||||
isOpen={isSelectEpisodeModalOpen}
|
||||
<SelectTrackModal
|
||||
isOpen={isSelectTrackModalOpen}
|
||||
id={id}
|
||||
artistId={series && series.id}
|
||||
seasonNumber={seasonNumber}
|
||||
onModalClose={this.onSelectEpisodeModalClose}
|
||||
artistId={artist && artist.id}
|
||||
albumId={album && album.id}
|
||||
onModalClose={this.onSelectTrackModalClose}
|
||||
/>
|
||||
|
||||
<SelectQualityModal
|
||||
|
@ -276,9 +277,9 @@ class InteractiveImportRow extends Component {
|
|||
InteractiveImportRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
relativePath: PropTypes.string.isRequired,
|
||||
series: PropTypes.object,
|
||||
seasonNumber: PropTypes.number,
|
||||
episodes: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
artist: PropTypes.object,
|
||||
album: PropTypes.object,
|
||||
tracks: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
quality: PropTypes.object,
|
||||
size: PropTypes.number.isRequired,
|
||||
rejections: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
|
@ -288,7 +289,7 @@ InteractiveImportRow.propTypes = {
|
|||
};
|
||||
|
||||
InteractiveImportRow.defaultProps = {
|
||||
episodes: []
|
||||
tracks: []
|
||||
};
|
||||
|
||||
export default InteractiveImportRow;
|
||||
|
|
|
@ -1,40 +0,0 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import styles from './SelectSeasonRow.css';
|
||||
|
||||
class SelectSeasonRow extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onPress = () => {
|
||||
this.props.onSeasonSelect(this.props.seasonNumber);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const seasonNumber = this.props.seasonNumber;
|
||||
|
||||
return (
|
||||
<Link
|
||||
className={styles.season}
|
||||
component="div"
|
||||
onPress={this.onPress}
|
||||
>
|
||||
{
|
||||
seasonNumber === 0 ? 'Specials' : `Season ${seasonNumber}`
|
||||
}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectSeasonRow.propTypes = {
|
||||
seasonNumber: PropTypes.number.isRequired,
|
||||
onSeasonSelect: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectSeasonRow;
|
|
@ -1,9 +1,9 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import SelectEpisodeModalContentConnector from './SelectEpisodeModalContentConnector';
|
||||
import SelectTrackModalContentConnector from './SelectTrackModalContentConnector';
|
||||
|
||||
class SelectEpisodeModal extends Component {
|
||||
class SelectTrackModal extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
@ -20,7 +20,7 @@ class SelectEpisodeModal extends Component {
|
|||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<SelectEpisodeModalContentConnector
|
||||
<SelectTrackModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
|
@ -29,9 +29,9 @@ class SelectEpisodeModal extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
SelectEpisodeModal.propTypes = {
|
||||
SelectTrackModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectEpisodeModal;
|
||||
export default SelectTrackModal;
|
|
@ -12,11 +12,11 @@ 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 SelectEpisodeRow from './SelectEpisodeRow';
|
||||
import SelectTrackRow from './SelectTrackRow';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'episodeNumber',
|
||||
name: 'trackNumber',
|
||||
label: '#',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
|
@ -25,15 +25,10 @@ const columns = [
|
|||
name: 'title',
|
||||
label: 'Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'airDate',
|
||||
label: 'Air Date',
|
||||
isVisible: true
|
||||
}
|
||||
];
|
||||
|
||||
class SelectEpisodeModalContent extends Component {
|
||||
class SelectTrackModalContent extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
@ -69,8 +64,8 @@ class SelectEpisodeModalContent extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
onEpisodesSelect = () => {
|
||||
this.props.onEpisodesSelect(this.getSelectedIds());
|
||||
onTracksSelect = () => {
|
||||
this.props.onTracksSelect(this.getSelectedIds());
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -94,12 +89,12 @@ class SelectEpisodeModalContent extends Component {
|
|||
selectedState
|
||||
} = this.state;
|
||||
|
||||
const errorMessage = error && error.message || 'Unable to load episodes';
|
||||
const errorMessage = error && error.message || 'Unable to load tracks';
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Manual Import - Select Episode(s)
|
||||
Manual Import - Select Track(s)
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
|
@ -129,12 +124,11 @@ class SelectEpisodeModalContent extends Component {
|
|||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<SelectEpisodeRow
|
||||
<SelectTrackRow
|
||||
key={item.id}
|
||||
id={item.id}
|
||||
episodeNumber={item.episodeNumber}
|
||||
trackNumber={item.trackNumber}
|
||||
title={item.title}
|
||||
airDate={item.airDate}
|
||||
isSelected={selectedState[item.id]}
|
||||
onSelectedChange={this.onSelectedChange}
|
||||
/>
|
||||
|
@ -147,7 +141,7 @@ class SelectEpisodeModalContent extends Component {
|
|||
|
||||
{
|
||||
isPopulated && !items.length &&
|
||||
'No episodes were found for the selected season'
|
||||
'No tracks were found for the selected album'
|
||||
}
|
||||
</ModalBody>
|
||||
|
||||
|
@ -158,9 +152,9 @@ class SelectEpisodeModalContent extends Component {
|
|||
|
||||
<Button
|
||||
kind={kinds.SUCCESS}
|
||||
onPress={this.onEpisodesSelect}
|
||||
onPress={this.onTracksSelect}
|
||||
>
|
||||
Select Episodes
|
||||
Select Tracks
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
|
@ -168,7 +162,7 @@ class SelectEpisodeModalContent extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
SelectEpisodeModalContent.propTypes = {
|
||||
SelectTrackModalContent.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
|
@ -176,8 +170,8 @@ SelectEpisodeModalContent.propTypes = {
|
|||
sortKey: PropTypes.string,
|
||||
sortDirection: PropTypes.string,
|
||||
onSortPress: PropTypes.func.isRequired,
|
||||
onEpisodesSelect: PropTypes.func.isRequired,
|
||||
onTracksSelect: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectEpisodeModalContent;
|
||||
export default SelectTrackModalContent;
|
|
@ -6,7 +6,7 @@ import connectSection from 'Store/connectSection';
|
|||
import { fetchEpisodes, setEpisodesSort, clearEpisodes } from 'Store/Actions/episodeActions';
|
||||
import { updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
|
||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||
import SelectEpisodeModalContent from './SelectEpisodeModalContent';
|
||||
import SelectTrackModalContent from './SelectTrackModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
|
@ -24,7 +24,7 @@ const mapDispatchToProps = {
|
|||
updateInteractiveImportItem
|
||||
};
|
||||
|
||||
class SelectEpisodeModalContentConnector extends Component {
|
||||
class SelectTrackModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
@ -32,10 +32,10 @@ class SelectEpisodeModalContentConnector extends Component {
|
|||
componentDidMount() {
|
||||
const {
|
||||
artistId,
|
||||
seasonNumber
|
||||
albumId
|
||||
} = this.props;
|
||||
|
||||
this.props.fetchEpisodes({ artistId, seasonNumber });
|
||||
this.props.fetchEpisodes({ artistId, albumId });
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
@ -51,8 +51,8 @@ class SelectEpisodeModalContentConnector extends Component {
|
|||
this.props.setEpisodesSort({ sortKey, sortDirection });
|
||||
}
|
||||
|
||||
onEpisodesSelect = (episodeIds) => {
|
||||
const episodes = _.reduce(this.props.items, (acc, item) => {
|
||||
onTracksSelect = (episodeIds) => {
|
||||
const tracks = _.reduce(this.props.items, (acc, item) => {
|
||||
if (episodeIds.indexOf(item.id) > -1) {
|
||||
acc.push(item);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ class SelectEpisodeModalContentConnector extends Component {
|
|||
|
||||
this.props.updateInteractiveImportItem({
|
||||
id: this.props.id,
|
||||
episodes: _.sortBy(episodes, 'episodeNumber')
|
||||
tracks: _.sortBy(tracks, 'trackNumber')
|
||||
});
|
||||
|
||||
this.props.onModalClose(true);
|
||||
|
@ -73,19 +73,19 @@ class SelectEpisodeModalContentConnector extends Component {
|
|||
|
||||
render() {
|
||||
return (
|
||||
<SelectEpisodeModalContent
|
||||
<SelectTrackModalContent
|
||||
{...this.props}
|
||||
onSortPress={this.onSortPress}
|
||||
onEpisodesSelect={this.onEpisodesSelect}
|
||||
onTracksSelect={this.onTracksSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectEpisodeModalContentConnector.propTypes = {
|
||||
SelectTrackModalContentConnector.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
artistId: PropTypes.number.isRequired,
|
||||
seasonNumber: PropTypes.number.isRequired,
|
||||
albumId: PropTypes.number.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
fetchEpisodes: PropTypes.func.isRequired,
|
||||
setEpisodesSort: PropTypes.func.isRequired,
|
||||
|
@ -100,4 +100,4 @@ export default connectSection(
|
|||
undefined,
|
||||
undefined,
|
||||
{ section: 'episodes' }
|
||||
)(SelectEpisodeModalContentConnector);
|
||||
)(SelectTrackModalContentConnector);
|
|
@ -4,7 +4,7 @@ import TableRowButton from 'Components/Table/TableRowButton';
|
|||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
|
||||
class SelectEpisodeRow extends Component {
|
||||
class SelectTrackRow extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
@ -24,9 +24,8 @@ class SelectEpisodeRow extends Component {
|
|||
render() {
|
||||
const {
|
||||
id,
|
||||
episodeNumber,
|
||||
trackNumber,
|
||||
title,
|
||||
airDate,
|
||||
isSelected,
|
||||
onSelectedChange
|
||||
} = this.props;
|
||||
|
@ -40,28 +39,24 @@ class SelectEpisodeRow extends Component {
|
|||
/>
|
||||
|
||||
<TableRowCell>
|
||||
{episodeNumber}
|
||||
{trackNumber}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
{title}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
{airDate}
|
||||
</TableRowCell>
|
||||
</TableRowButton>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectEpisodeRow.propTypes = {
|
||||
SelectTrackRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
episodeNumber: PropTypes.number.isRequired,
|
||||
trackNumber: PropTypes.number.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
airDate: PropTypes.string.isRequired,
|
||||
isSelected: PropTypes.bool,
|
||||
onSelectedChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectEpisodeRow;
|
||||
export default SelectTrackRow;
|
Loading…
Add table
Add a link
Reference in a new issue