mirror of
https://github.com/lidarr/lidarr.git
synced 2025-07-16 10:03:51 -07:00
[UI Work] Artist Detail, Album Dialog, Album Search, Album Missing Search
This commit is contained in:
parent
5fec72395c
commit
0a7f18e843
39 changed files with 559 additions and 709 deletions
|
@ -10,13 +10,13 @@ class AlbumStudioAlbum extends Component {
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onSeasonMonitoredPress = () => {
|
onAlbumMonitoredPress = () => {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
monitored
|
monitored
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this.props.onSeasonMonitoredPress(id, !monitored);
|
this.props.onAlbumMonitoredPress(id, !monitored);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -43,7 +43,7 @@ class AlbumStudioAlbum extends Component {
|
||||||
<MonitorToggleButton
|
<MonitorToggleButton
|
||||||
monitored={monitored}
|
monitored={monitored}
|
||||||
isSaving={isSaving}
|
isSaving={isSaving}
|
||||||
onPress={this.onSeasonMonitoredPress}
|
onPress={this.onAlbumMonitoredPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
|
@ -75,7 +75,7 @@ AlbumStudioAlbum.propTypes = {
|
||||||
monitored: PropTypes.bool.isRequired,
|
monitored: PropTypes.bool.isRequired,
|
||||||
statistics: PropTypes.object.isRequired,
|
statistics: PropTypes.object.isRequired,
|
||||||
isSaving: PropTypes.bool.isRequired,
|
isSaving: PropTypes.bool.isRequired,
|
||||||
onSeasonMonitoredPress: PropTypes.func.isRequired
|
onAlbumMonitoredPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
AlbumStudioAlbum.defaultProps = {
|
AlbumStudioAlbum.defaultProps = {
|
||||||
|
|
|
@ -26,8 +26,8 @@ class AlbumStudioRow extends Component {
|
||||||
isSaving,
|
isSaving,
|
||||||
isSelected,
|
isSelected,
|
||||||
onSelectedChange,
|
onSelectedChange,
|
||||||
onSeriesMonitoredPress,
|
onArtistMonitoredPress,
|
||||||
onSeasonMonitoredPress
|
onAlbumMonitoredPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -41,7 +41,7 @@ class AlbumStudioRow extends Component {
|
||||||
<TableRowCell className={styles.status}>
|
<TableRowCell className={styles.status}>
|
||||||
<Icon
|
<Icon
|
||||||
className={styles.statusIcon}
|
className={styles.statusIcon}
|
||||||
name={status === 'ended' ? icons.SERIES_ENDED : icons.SERIES_CONTINUING}
|
name={status === 'ended' ? icons.ARTIST_ENDED : icons.ARTIST_CONTINUING}
|
||||||
title={status === 'ended' ? 'Ended' : 'Continuing'}
|
title={status === 'ended' ? 'Ended' : 'Continuing'}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
@ -58,7 +58,7 @@ class AlbumStudioRow extends Component {
|
||||||
<MonitorToggleButton
|
<MonitorToggleButton
|
||||||
monitored={monitored}
|
monitored={monitored}
|
||||||
isSaving={isSaving}
|
isSaving={isSaving}
|
||||||
onPress={onSeriesMonitoredPress}
|
onPress={onArtistMonitoredPress}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ class AlbumStudioRow extends Component {
|
||||||
<AlbumStudioAlbum
|
<AlbumStudioAlbum
|
||||||
key={season.id}
|
key={season.id}
|
||||||
{...season}
|
{...season}
|
||||||
onSeasonMonitoredPress={onSeasonMonitoredPress}
|
onAlbumMonitoredPress={onAlbumMonitoredPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
|
@ -90,8 +90,8 @@ AlbumStudioRow.propTypes = {
|
||||||
isSaving: PropTypes.bool.isRequired,
|
isSaving: PropTypes.bool.isRequired,
|
||||||
isSelected: PropTypes.bool,
|
isSelected: PropTypes.bool,
|
||||||
onSelectedChange: PropTypes.func.isRequired,
|
onSelectedChange: PropTypes.func.isRequired,
|
||||||
onSeriesMonitoredPress: PropTypes.func.isRequired,
|
onArtistMonitoredPress: PropTypes.func.isRequired,
|
||||||
onSeasonMonitoredPress: PropTypes.func.isRequired
|
onAlbumMonitoredPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
AlbumStudioRow.defaultProps = {
|
AlbumStudioRow.defaultProps = {
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
||||||
import { toggleSeriesMonitored, toggleSeasonMonitored } from 'Store/Actions/artistActions';
|
import { toggleSeriesMonitored, toggleSeasonMonitored } from 'Store/Actions/artistActions';
|
||||||
|
import { toggleEpisodeMonitored } from 'Store/Actions/episodeActions';
|
||||||
import AlbumStudioRow from './AlbumStudioRow';
|
import AlbumStudioRow from './AlbumStudioRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
|
@ -25,7 +26,8 @@ function createMapStateToProps() {
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
toggleSeriesMonitored,
|
toggleSeriesMonitored,
|
||||||
toggleSeasonMonitored
|
toggleSeasonMonitored,
|
||||||
|
toggleEpisodeMonitored
|
||||||
};
|
};
|
||||||
|
|
||||||
class AlbumStudioRowConnector extends Component {
|
class AlbumStudioRowConnector extends Component {
|
||||||
|
@ -33,7 +35,7 @@ class AlbumStudioRowConnector extends Component {
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onSeriesMonitoredPress = () => {
|
onArtistMonitoredPress = () => {
|
||||||
const {
|
const {
|
||||||
artistId,
|
artistId,
|
||||||
monitored
|
monitored
|
||||||
|
@ -45,11 +47,10 @@ class AlbumStudioRowConnector extends Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSeasonMonitoredPress = (seasonNumber, monitored) => {
|
onAlbumMonitoredPress = (episodeId, monitored) => {
|
||||||
this.props.toggleSeasonMonitored({
|
this.props.toggleEpisodeMonitored({
|
||||||
artistId: this.props.artistId,
|
episodeId,
|
||||||
seasonNumber,
|
monitored: !monitored
|
||||||
monitored
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,8 +61,8 @@ class AlbumStudioRowConnector extends Component {
|
||||||
return (
|
return (
|
||||||
<AlbumStudioRow
|
<AlbumStudioRow
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onSeriesMonitoredPress={this.onSeriesMonitoredPress}
|
onArtistMonitoredPress={this.onArtistMonitoredPress}
|
||||||
onSeasonMonitoredPress={this.onSeasonMonitoredPress}
|
onAlbumMonitoredPress={this.onAlbumMonitoredPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +72,8 @@ AlbumStudioRowConnector.propTypes = {
|
||||||
artistId: PropTypes.number.isRequired,
|
artistId: PropTypes.number.isRequired,
|
||||||
monitored: PropTypes.bool.isRequired,
|
monitored: PropTypes.bool.isRequired,
|
||||||
toggleSeriesMonitored: PropTypes.func.isRequired,
|
toggleSeriesMonitored: PropTypes.func.isRequired,
|
||||||
toggleSeasonMonitored: PropTypes.func.isRequired
|
toggleSeasonMonitored: PropTypes.func.isRequired,
|
||||||
|
toggleEpisodeMonitored: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(AlbumStudioRowConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AlbumStudioRowConnector);
|
||||||
|
|
|
@ -13,7 +13,7 @@ import AddNewArtistConnector from 'AddArtist/AddNewArtist/AddNewArtistConnector'
|
||||||
import ImportArtist from 'AddArtist/ImportArtist/ImportArtist';
|
import ImportArtist from 'AddArtist/ImportArtist/ImportArtist';
|
||||||
import ArtistEditorConnector from 'Artist/Editor/ArtistEditorConnector';
|
import ArtistEditorConnector from 'Artist/Editor/ArtistEditorConnector';
|
||||||
import AlbumStudioConnector from 'AlbumStudio/AlbumStudioConnector';
|
import AlbumStudioConnector from 'AlbumStudio/AlbumStudioConnector';
|
||||||
import SeriesDetailsPageConnector from 'Artist/Details/SeriesDetailsPageConnector';
|
import ArtistDetailsPageConnector from 'Artist/Details/ArtistDetailsPageConnector';
|
||||||
import CalendarPageConnector from 'Calendar/CalendarPageConnector';
|
import CalendarPageConnector from 'Calendar/CalendarPageConnector';
|
||||||
import HistoryConnector from 'Activity/History/HistoryConnector';
|
import HistoryConnector from 'Activity/History/HistoryConnector';
|
||||||
import QueueConnector from 'Activity/Queue/QueueConnector';
|
import QueueConnector from 'Activity/Queue/QueueConnector';
|
||||||
|
@ -93,7 +93,7 @@ function App({ store, history }) {
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/artist/:nameSlug"
|
path="/artist/:nameSlug"
|
||||||
component={SeriesDetailsPageConnector}
|
component={ArtistDetailsPageConnector}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
|
|
|
@ -10,15 +10,6 @@
|
||||||
width: 42px;
|
width: 42px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.episodeNumber {
|
|
||||||
composes: cell from 'Components/Table/Cells/TableRowCell.css';
|
|
||||||
|
|
||||||
width: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.language,
|
|
||||||
.audio,
|
|
||||||
.video,
|
|
||||||
.status {
|
.status {
|
||||||
composes: cell from 'Components/Table/Cells/TableRowCell.css';
|
composes: cell from 'Components/Table/Cells/TableRowCell.css';
|
||||||
|
|
219
frontend/src/Artist/Details/AlbumRow.js
Normal file
219
frontend/src/Artist/Details/AlbumRow.js
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import MonitorToggleButton from 'Components/MonitorToggleButton';
|
||||||
|
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||||
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
|
import TableRow from 'Components/Table/TableRow';
|
||||||
|
import Label from 'Components/Label';
|
||||||
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
|
import formatTimeSpan from 'Utilities/Date/formatTimeSpan';
|
||||||
|
import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector';
|
||||||
|
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
||||||
|
|
||||||
|
import styles from './AlbumRow.css';
|
||||||
|
|
||||||
|
function getEpisodeCountKind(monitored, episodeFileCount, episodeCount) {
|
||||||
|
if (episodeFileCount === episodeCount && episodeCount > 0) {
|
||||||
|
return kinds.SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!monitored) {
|
||||||
|
return kinds.WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kinds.DANGER;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AlbumRow extends Component {
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifecycle
|
||||||
|
|
||||||
|
constructor(props, context) {
|
||||||
|
super(props, context);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isDetailsModalOpen: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Listeners
|
||||||
|
|
||||||
|
onManualSearchPress = () => {
|
||||||
|
this.setState({ isDetailsModalOpen: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
onDetailsModalClose = () => {
|
||||||
|
this.setState({ isDetailsModalOpen: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
onMonitorAlbumPress = (monitored, options) => {
|
||||||
|
this.props.onMonitorAlbumPress(this.props.id, monitored, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Render
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
id,
|
||||||
|
artistId,
|
||||||
|
monitored,
|
||||||
|
statistics,
|
||||||
|
duration,
|
||||||
|
releaseDate,
|
||||||
|
title,
|
||||||
|
isSaving,
|
||||||
|
artistMonitored,
|
||||||
|
path,
|
||||||
|
columns
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const {
|
||||||
|
trackCount,
|
||||||
|
trackFileCount,
|
||||||
|
totalTrackCount
|
||||||
|
} = statistics;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TableRow>
|
||||||
|
{
|
||||||
|
columns.map((column) => {
|
||||||
|
const {
|
||||||
|
name,
|
||||||
|
isVisible
|
||||||
|
} = column;
|
||||||
|
|
||||||
|
if (!isVisible) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'monitored') {
|
||||||
|
return (
|
||||||
|
<TableRowCell
|
||||||
|
key={name}
|
||||||
|
className={styles.monitored}
|
||||||
|
>
|
||||||
|
<MonitorToggleButton
|
||||||
|
monitored={monitored}
|
||||||
|
isDisabled={!artistMonitored}
|
||||||
|
isSaving={isSaving}
|
||||||
|
onPress={this.onMonitorAlbumPress}
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'title') {
|
||||||
|
return (
|
||||||
|
<TableRowCell
|
||||||
|
key={name}
|
||||||
|
className={styles.title}
|
||||||
|
>
|
||||||
|
<EpisodeTitleLink
|
||||||
|
episodeId={id}
|
||||||
|
artistId={artistId}
|
||||||
|
episodeTitle={title}
|
||||||
|
showOpenSeriesButton={false}
|
||||||
|
/>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'path') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
{
|
||||||
|
path
|
||||||
|
}
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'trackCount') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
{
|
||||||
|
statistics.trackCount
|
||||||
|
}
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'duration') {
|
||||||
|
return (
|
||||||
|
<TableRowCell key={name}>
|
||||||
|
{
|
||||||
|
formatTimeSpan(duration)
|
||||||
|
}
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'releaseDate') {
|
||||||
|
return (
|
||||||
|
<RelativeDateCellConnector
|
||||||
|
key={name}
|
||||||
|
date={releaseDate}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'status') {
|
||||||
|
return (
|
||||||
|
<TableRowCell
|
||||||
|
key={name}
|
||||||
|
className={styles.status}
|
||||||
|
>
|
||||||
|
<Label
|
||||||
|
title={`${totalTrackCount} tracks total. ${trackFileCount} tracks with files.`}
|
||||||
|
kind={getEpisodeCountKind(monitored, trackFileCount, trackCount)}
|
||||||
|
size={sizes.MEDIUM}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
<span>{trackFileCount} / {trackCount}</span>
|
||||||
|
}
|
||||||
|
</Label>
|
||||||
|
</TableRowCell>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'actions') {
|
||||||
|
return (
|
||||||
|
<EpisodeSearchCellConnector
|
||||||
|
key={name}
|
||||||
|
episodeId={id}
|
||||||
|
artistId={artistId}
|
||||||
|
episodeTitle={title}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</TableRow>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AlbumRow.propTypes = {
|
||||||
|
id: PropTypes.number.isRequired,
|
||||||
|
artistId: PropTypes.number.isRequired,
|
||||||
|
monitored: PropTypes.bool.isRequired,
|
||||||
|
releaseDate: PropTypes.string.isRequired,
|
||||||
|
duration: PropTypes.number.isRequired,
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
isSaving: PropTypes.bool,
|
||||||
|
unverifiedSceneNumbering: PropTypes.bool,
|
||||||
|
artistMonitored: PropTypes.bool.isRequired,
|
||||||
|
statistics: PropTypes.object.isRequired,
|
||||||
|
path: PropTypes.string,
|
||||||
|
mediaInfo: PropTypes.object,
|
||||||
|
alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
onMonitorAlbumPress: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AlbumRow;
|
|
@ -4,7 +4,7 @@ import { createSelector } from 'reselect';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
||||||
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
|
import createEpisodeFileSelector from 'Store/Selectors/createEpisodeFileSelector';
|
||||||
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
||||||
import EpisodeRow from './EpisodeRow';
|
import AlbumRow from './AlbumRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
|
@ -17,7 +17,7 @@ function createMapStateToProps() {
|
||||||
const alternateTitles = sceneSeasonNumber ? _.filter(series.alternateTitles, { sceneSeasonNumber }) : [];
|
const alternateTitles = sceneSeasonNumber ? _.filter(series.alternateTitles, { sceneSeasonNumber }) : [];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
seriesMonitored: series.monitored,
|
artistMonitored: series.monitored,
|
||||||
seriesType: series.seriesType,
|
seriesType: series.seriesType,
|
||||||
episodeFilePath: episodeFile ? episodeFile.path : null,
|
episodeFilePath: episodeFile ? episodeFile.path : null,
|
||||||
episodeFileRelativePath: episodeFile ? episodeFile.relativePath : null,
|
episodeFileRelativePath: episodeFile ? episodeFile.relativePath : null,
|
||||||
|
@ -26,4 +26,4 @@ function createMapStateToProps() {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(createMapStateToProps)(EpisodeRow);
|
export default connect(createMapStateToProps)(AlbumRow);
|
|
@ -1,8 +1,8 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styles from './SeriesAlternateTitles.css';
|
import styles from './ArtistAlternateTitles.css';
|
||||||
|
|
||||||
function SeriesAlternateTitles({ alternateTitles }) {
|
function ArtistAlternateTitles({ alternateTitles }) {
|
||||||
return (
|
return (
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
|
@ -21,8 +21,8 @@ function SeriesAlternateTitles({ alternateTitles }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SeriesAlternateTitles.propTypes = {
|
ArtistAlternateTitles.propTypes = {
|
||||||
alternateTitles: PropTypes.arrayOf(PropTypes.string).isRequired
|
alternateTitles: PropTypes.arrayOf(PropTypes.string).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SeriesAlternateTitles;
|
export default ArtistAlternateTitles;
|
|
@ -61,11 +61,11 @@
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.seriesNavigationButtons {
|
.artistNavigationButtons {
|
||||||
white-space: no-wrap;
|
white-space: no-wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.seriesNavigationButton {
|
.artistNavigationButton {
|
||||||
composes: button from 'Components/Link/IconButton.css';
|
composes: button from 'Components/Link/IconButton.css';
|
||||||
|
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
|
@ -90,7 +90,6 @@
|
||||||
|
|
||||||
.sizeOnDisk,
|
.sizeOnDisk,
|
||||||
.qualityProfileName,
|
.qualityProfileName,
|
||||||
.network,
|
|
||||||
.links,
|
.links,
|
||||||
.tags {
|
.tags {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
|
@ -24,11 +24,29 @@ import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfil
|
||||||
import ArtistPoster from 'Artist/ArtistPoster';
|
import ArtistPoster from 'Artist/ArtistPoster';
|
||||||
import EditArtistModalConnector from 'Artist/Edit/EditArtistModalConnector';
|
import EditArtistModalConnector from 'Artist/Edit/EditArtistModalConnector';
|
||||||
import DeleteArtistModal from 'Artist/Delete/DeleteArtistModal';
|
import DeleteArtistModal from 'Artist/Delete/DeleteArtistModal';
|
||||||
import SeriesAlternateTitles from './SeriesAlternateTitles';
|
import ArtistAlternateTitles from './ArtistAlternateTitles';
|
||||||
import SeriesDetailsSeasonConnector from './SeriesDetailsSeasonConnector';
|
import ArtistDetailsSeasonConnector from './ArtistDetailsSeasonConnector';
|
||||||
import SeriesTagsConnector from './SeriesTagsConnector';
|
import ArtistTagsConnector from './ArtistTagsConnector';
|
||||||
import SeriesDetailsLinks from './SeriesDetailsLinks';
|
import ArtistDetailsLinks from './ArtistDetailsLinks';
|
||||||
import styles from './SeriesDetails.css';
|
import styles from './ArtistDetails.css';
|
||||||
|
|
||||||
|
const albumTypes = [
|
||||||
|
{
|
||||||
|
name: 'album',
|
||||||
|
label: 'Album',
|
||||||
|
isVisible: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'single',
|
||||||
|
label: 'Single',
|
||||||
|
isVisible: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ep',
|
||||||
|
label: 'EP',
|
||||||
|
isVisible: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
function getFanartUrl(images) {
|
function getFanartUrl(images) {
|
||||||
const fanartImage = _.find(images, { coverType: 'fanart' });
|
const fanartImage = _.find(images, { coverType: 'fanart' });
|
||||||
|
@ -46,7 +64,7 @@ function getExpandedState(newState) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class SeriesDetails extends Component {
|
class ArtistDetails extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
|
@ -133,8 +151,6 @@ class SeriesDetails extends Component {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
foreignArtistId,
|
foreignArtistId,
|
||||||
tvMazeId,
|
|
||||||
imdbId,
|
|
||||||
artistName,
|
artistName,
|
||||||
ratings,
|
ratings,
|
||||||
sizeOnDisk,
|
sizeOnDisk,
|
||||||
|
@ -142,7 +158,6 @@ class SeriesDetails extends Component {
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
monitored,
|
monitored,
|
||||||
status,
|
status,
|
||||||
network,
|
|
||||||
overview,
|
overview,
|
||||||
images,
|
images,
|
||||||
albums,
|
albums,
|
||||||
|
@ -154,8 +169,8 @@ class SeriesDetails extends Component {
|
||||||
isPopulated,
|
isPopulated,
|
||||||
episodesError,
|
episodesError,
|
||||||
episodeFilesError,
|
episodeFilesError,
|
||||||
previousSeries,
|
previousArtist,
|
||||||
nextSeries,
|
nextArtist,
|
||||||
onRefreshPress,
|
onRefreshPress,
|
||||||
onSearchPress
|
onSearchPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -172,12 +187,12 @@ class SeriesDetails extends Component {
|
||||||
|
|
||||||
const continuing = status === 'continuing';
|
const continuing = status === 'continuing';
|
||||||
|
|
||||||
let episodeFilesCountMessage = 'No episode files';
|
let episodeFilesCountMessage = 'No track files';
|
||||||
|
|
||||||
if (trackFileCount === 1) {
|
if (trackFileCount === 1) {
|
||||||
episodeFilesCountMessage = '1 episode file';
|
episodeFilesCountMessage = '1 track file';
|
||||||
} else if (trackFileCount > 1) {
|
} else if (trackFileCount > 1) {
|
||||||
episodeFilesCountMessage = `${trackFileCount} episode files`;
|
episodeFilesCountMessage = `${trackFileCount} track files`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let expandIcon = icons.EXPAND_INDETERMINATE;
|
let expandIcon = icons.EXPAND_INDETERMINATE;
|
||||||
|
@ -217,7 +232,7 @@ class SeriesDetails extends Component {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Manage Episodes"
|
label="Manage Tracks"
|
||||||
iconName={icons.EPISODE_FILE}
|
iconName={icons.EPISODE_FILE}
|
||||||
onPress={this.onManageEpisodesPress}
|
onPress={this.onManageEpisodesPress}
|
||||||
/>
|
/>
|
||||||
|
@ -281,28 +296,28 @@ class SeriesDetails extends Component {
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
title="Alternate Titles"
|
title="Alternate Titles"
|
||||||
body={<SeriesAlternateTitles alternateTitles={alternateTitles} />}
|
body={<ArtistAlternateTitles alternateTitles={alternateTitles} />}
|
||||||
position={tooltipPositions.BOTTOM}
|
position={tooltipPositions.BOTTOM}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.seriesNavigationButtons}>
|
<div className={styles.artistNavigationButtons}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.seriesNavigationButton}
|
className={styles.artistNavigationButton}
|
||||||
name={icons.ARROW_LEFT}
|
name={icons.ARROW_LEFT}
|
||||||
size={30}
|
size={30}
|
||||||
title={`Go to ${previousSeries.artistName}`}
|
title={`Go to ${previousArtist.artistName}`}
|
||||||
to={`/artist/${previousSeries.nameSlug}`}
|
to={`/artist/${previousArtist.nameSlug}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.seriesNavigationButton}
|
className={styles.artistNavigationButton}
|
||||||
name={icons.ARROW_RIGHT}
|
name={icons.ARROW_RIGHT}
|
||||||
size={30}
|
size={30}
|
||||||
title={`Go to ${nextSeries.artistName}`}
|
title={`Go to ${nextArtist.artistName}`}
|
||||||
to={`/artist/${nextSeries.nameSlug}`}
|
to={`/artist/${nextArtist.nameSlug}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -369,11 +384,11 @@ class SeriesDetails extends Component {
|
||||||
|
|
||||||
<Label
|
<Label
|
||||||
className={styles.detailsLabel}
|
className={styles.detailsLabel}
|
||||||
title={continuing ? 'More episodes/another season is expected' : 'No additional episodes or or another season is expected'}
|
title={continuing ? 'More albums are expected' : 'No additional albums are expected'}
|
||||||
size={sizes.LARGE}
|
size={sizes.LARGE}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
name={continuing ? icons.SERIES_CONTINUING : icons.SERIES_ENDED}
|
name={continuing ? icons.ARTIST_CONTINUING : icons.ARTIST_ENDED}
|
||||||
size={17}
|
size={17}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -382,24 +397,6 @@ class SeriesDetails extends Component {
|
||||||
</span>
|
</span>
|
||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
{
|
|
||||||
!!network &&
|
|
||||||
<Label
|
|
||||||
className={styles.detailsLabel}
|
|
||||||
title="Network"
|
|
||||||
size={sizes.LARGE}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name={icons.NETWORK}
|
|
||||||
size={17}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<span className={styles.qualityProfileName}>
|
|
||||||
{network}
|
|
||||||
</span>
|
|
||||||
</Label>
|
|
||||||
}
|
|
||||||
|
|
||||||
<Tooltip
|
<Tooltip
|
||||||
anchor={
|
anchor={
|
||||||
<Label
|
<Label
|
||||||
|
@ -417,10 +414,8 @@ class SeriesDetails extends Component {
|
||||||
</Label>
|
</Label>
|
||||||
}
|
}
|
||||||
tooltip={
|
tooltip={
|
||||||
<SeriesDetailsLinks
|
<ArtistDetailsLinks
|
||||||
foreignArtistId={foreignArtistId}
|
foreignArtistId={foreignArtistId}
|
||||||
tvMazeId={tvMazeId}
|
|
||||||
imdbId={imdbId}
|
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
kind={kinds.INVERSE}
|
kind={kinds.INVERSE}
|
||||||
|
@ -445,7 +440,7 @@ class SeriesDetails extends Component {
|
||||||
</span>
|
</span>
|
||||||
</Label>
|
</Label>
|
||||||
}
|
}
|
||||||
tooltip={<SeriesTagsConnector artistId={id} />}
|
tooltip={<ArtistTagsConnector artistId={id} />}
|
||||||
kind={kinds.INVERSE}
|
kind={kinds.INVERSE}
|
||||||
position={tooltipPositions.BOTTOM}
|
position={tooltipPositions.BOTTOM}
|
||||||
/>
|
/>
|
||||||
|
@ -477,18 +472,17 @@ class SeriesDetails extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isPopulated && !!albums.length &&
|
isPopulated && !!albumTypes.length &&
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
albums.slice(0).reverse().map((season) => {
|
albumTypes.slice(0).map((season) => {
|
||||||
return (
|
return (
|
||||||
<SeriesDetailsSeasonConnector
|
<ArtistDetailsSeasonConnector
|
||||||
key={season.id}
|
key={season.name}
|
||||||
artistId={id}
|
artistId={id}
|
||||||
albumId={season.id}
|
label={season.label}
|
||||||
statistics={season.statistics}
|
|
||||||
{...season}
|
{...season}
|
||||||
isExpanded={expandedState[season.id]}
|
isExpanded={expandedState[season.name]}
|
||||||
onExpandPress={this.onExpandPress}
|
onExpandPress={this.onExpandPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -536,11 +530,9 @@ class SeriesDetails extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SeriesDetails.propTypes = {
|
ArtistDetails.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
foreignArtistId: PropTypes.string.isRequired,
|
foreignArtistId: PropTypes.string.isRequired,
|
||||||
tvMazeId: PropTypes.number,
|
|
||||||
imdbId: PropTypes.string,
|
|
||||||
artistName: PropTypes.string.isRequired,
|
artistName: PropTypes.string.isRequired,
|
||||||
ratings: PropTypes.object.isRequired,
|
ratings: PropTypes.object.isRequired,
|
||||||
sizeOnDisk: PropTypes.number.isRequired,
|
sizeOnDisk: PropTypes.number.isRequired,
|
||||||
|
@ -548,7 +540,6 @@ SeriesDetails.propTypes = {
|
||||||
qualityProfileId: PropTypes.number.isRequired,
|
qualityProfileId: PropTypes.number.isRequired,
|
||||||
monitored: PropTypes.bool.isRequired,
|
monitored: PropTypes.bool.isRequired,
|
||||||
status: PropTypes.string.isRequired,
|
status: PropTypes.string.isRequired,
|
||||||
network: PropTypes.string,
|
|
||||||
overview: PropTypes.string.isRequired,
|
overview: PropTypes.string.isRequired,
|
||||||
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
albums: PropTypes.arrayOf(PropTypes.object).isRequired,
|
albums: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
@ -560,10 +551,10 @@ SeriesDetails.propTypes = {
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
episodesError: PropTypes.object,
|
episodesError: PropTypes.object,
|
||||||
episodeFilesError: PropTypes.object,
|
episodeFilesError: PropTypes.object,
|
||||||
previousSeries: PropTypes.object.isRequired,
|
previousArtist: PropTypes.object.isRequired,
|
||||||
nextSeries: PropTypes.object.isRequired,
|
nextArtist: PropTypes.object.isRequired,
|
||||||
onRefreshPress: PropTypes.func.isRequired,
|
onRefreshPress: PropTypes.func.isRequired,
|
||||||
onSearchPress: PropTypes.func.isRequired
|
onSearchPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SeriesDetails;
|
export default ArtistDetails;
|
|
@ -11,7 +11,7 @@ import { fetchEpisodeFiles, clearEpisodeFiles } from 'Store/Actions/episodeFileA
|
||||||
import { fetchQueueDetails, clearQueueDetails } from 'Store/Actions/queueActions';
|
import { fetchQueueDetails, clearQueueDetails } from 'Store/Actions/queueActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import SeriesDetails from './SeriesDetails';
|
import ArtistDetails from './ArtistDetails';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
|
@ -21,7 +21,7 @@ function createMapStateToProps() {
|
||||||
createAllArtistSelector(),
|
createAllArtistSelector(),
|
||||||
createCommandsSelector(),
|
createCommandsSelector(),
|
||||||
(nameSlug, episodes, episodeFiles, allSeries, commands) => {
|
(nameSlug, episodes, episodeFiles, allSeries, commands) => {
|
||||||
const sortedArtist = _.orderBy(allSeries, 'sortTitle');
|
const sortedArtist = _.orderBy(allSeries, 'sortName');
|
||||||
const seriesIndex = _.findIndex(sortedArtist, { nameSlug });
|
const seriesIndex = _.findIndex(sortedArtist, { nameSlug });
|
||||||
const series = sortedArtist[seriesIndex];
|
const series = sortedArtist[seriesIndex];
|
||||||
|
|
||||||
|
@ -29,15 +29,15 @@ function createMapStateToProps() {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const previousSeries = sortedArtist[seriesIndex - 1] || _.last(sortedArtist);
|
const previousArtist = sortedArtist[seriesIndex - 1] || _.last(sortedArtist);
|
||||||
const nextSeries = sortedArtist[seriesIndex + 1] || _.first(sortedArtist);
|
const nextArtist = sortedArtist[seriesIndex + 1] || _.first(sortedArtist);
|
||||||
const isSeriesRefreshing = !!findCommand(commands, { name: commandNames.REFRESH_ARTIST, artistId: series.id });
|
const isArtistRefreshing = !!findCommand(commands, { name: commandNames.REFRESH_ARTIST, artistId: series.id });
|
||||||
const allSeriesRefreshing = _.some(commands, (command) => command.name === commandNames.REFRESH_ARTIST && !command.body.artistId);
|
const allArtistRefreshing = _.some(commands, (command) => command.name === commandNames.REFRESH_ARTIST && !command.body.artistId);
|
||||||
const isRefreshing = isSeriesRefreshing || allSeriesRefreshing;
|
const isRefreshing = isArtistRefreshing || allArtistRefreshing;
|
||||||
const isSearching = !!findCommand(commands, { name: commandNames.ARTIST_SEARCH, artistId: series.id });
|
const isSearching = !!findCommand(commands, { name: commandNames.ARTIST_SEARCH, artistId: series.id });
|
||||||
const isRenamingFiles = !!findCommand(commands, { name: commandNames.RENAME_FILES, artistId: series.id });
|
const isRenamingFiles = !!findCommand(commands, { name: commandNames.RENAME_FILES, artistId: series.id });
|
||||||
const isRenamingSeriesCommand = findCommand(commands, { name: commandNames.RENAME_ARTIST });
|
const isRenamingArtistCommand = findCommand(commands, { name: commandNames.RENAME_ARTIST });
|
||||||
const isRenamingSeries = !!(isRenamingSeriesCommand && isRenamingSeriesCommand.body.artistId.indexOf(series.id) > -1);
|
const isRenamingArtist = !!(isRenamingArtistCommand && isRenamingArtistCommand.body.artistId.indexOf(series.id) > -1);
|
||||||
|
|
||||||
const isFetching = episodes.isFetching || episodeFiles.isFetching;
|
const isFetching = episodes.isFetching || episodeFiles.isFetching;
|
||||||
const isPopulated = episodes.isPopulated && episodeFiles.isPopulated;
|
const isPopulated = episodes.isPopulated && episodeFiles.isPopulated;
|
||||||
|
@ -58,13 +58,13 @@ function createMapStateToProps() {
|
||||||
isRefreshing,
|
isRefreshing,
|
||||||
isSearching,
|
isSearching,
|
||||||
isRenamingFiles,
|
isRenamingFiles,
|
||||||
isRenamingSeries,
|
isRenamingArtist,
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
episodesError,
|
episodesError,
|
||||||
episodeFilesError,
|
episodeFilesError,
|
||||||
previousSeries,
|
previousArtist,
|
||||||
nextSeries
|
nextArtist
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -80,7 +80,7 @@ const mapDispatchToProps = {
|
||||||
executeCommand
|
executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class SeriesDetailsConnector extends Component {
|
class ArtistDetailsConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
|
@ -94,13 +94,13 @@ class SeriesDetailsConnector extends Component {
|
||||||
id,
|
id,
|
||||||
isRefreshing,
|
isRefreshing,
|
||||||
isRenamingFiles,
|
isRenamingFiles,
|
||||||
isRenamingSeries
|
isRenamingArtist
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(prevProps.isRefreshing && !isRefreshing) ||
|
(prevProps.isRefreshing && !isRefreshing) ||
|
||||||
(prevProps.isRenamingFiles && !isRenamingFiles) ||
|
(prevProps.isRenamingFiles && !isRenamingFiles) ||
|
||||||
(prevProps.isRenamingSeries && !isRenamingSeries)
|
(prevProps.isRenamingArtist && !isRenamingArtist)
|
||||||
) {
|
) {
|
||||||
this._populate();
|
this._populate();
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,7 @@ class SeriesDetailsConnector extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<SeriesDetails
|
<ArtistDetails
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onRefreshPress={this.onRefreshPress}
|
onRefreshPress={this.onRefreshPress}
|
||||||
onSearchPress={this.onSearchPress}
|
onSearchPress={this.onSearchPress}
|
||||||
|
@ -166,12 +166,12 @@ class SeriesDetailsConnector extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SeriesDetailsConnector.propTypes = {
|
ArtistDetailsConnector.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
nameSlug: PropTypes.string.isRequired,
|
nameSlug: PropTypes.string.isRequired,
|
||||||
isRefreshing: PropTypes.bool.isRequired,
|
isRefreshing: PropTypes.bool.isRequired,
|
||||||
isRenamingFiles: PropTypes.bool.isRequired,
|
isRenamingFiles: PropTypes.bool.isRequired,
|
||||||
isRenamingSeries: PropTypes.bool.isRequired,
|
isRenamingArtist: PropTypes.bool.isRequired,
|
||||||
fetchEpisodes: PropTypes.func.isRequired,
|
fetchEpisodes: PropTypes.func.isRequired,
|
||||||
clearEpisodes: PropTypes.func.isRequired,
|
clearEpisodes: PropTypes.func.isRequired,
|
||||||
fetchEpisodeFiles: PropTypes.func.isRequired,
|
fetchEpisodeFiles: PropTypes.func.isRequired,
|
||||||
|
@ -181,4 +181,4 @@ SeriesDetailsConnector.propTypes = {
|
||||||
executeCommand: PropTypes.func.isRequired
|
executeCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(SeriesDetailsConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistDetailsConnector);
|
36
frontend/src/Artist/Details/ArtistDetailsLinks.js
Normal file
36
frontend/src/Artist/Details/ArtistDetailsLinks.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import React from 'react';
|
||||||
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
|
import Label from 'Components/Label';
|
||||||
|
import Link from 'Components/Link/Link';
|
||||||
|
import styles from './ArtistDetailsLinks.css';
|
||||||
|
|
||||||
|
function ArtistDetailsLinks(props) {
|
||||||
|
const {
|
||||||
|
foreignArtistId
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.links}>
|
||||||
|
<Link
|
||||||
|
className={styles.link}
|
||||||
|
to={`https://musicbrainz.org/artist/${foreignArtistId}`}
|
||||||
|
>
|
||||||
|
<Label
|
||||||
|
className={styles.linkLabel}
|
||||||
|
kind={kinds.INFO}
|
||||||
|
size={sizes.LARGE}
|
||||||
|
>
|
||||||
|
Musicbrainz
|
||||||
|
</Label>
|
||||||
|
</Link>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ArtistDetailsLinks.propTypes = {
|
||||||
|
foreignArtistId: PropTypes.string.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ArtistDetailsLinks;
|
|
@ -6,7 +6,7 @@ import { createSelector } from 'reselect';
|
||||||
import { push } from 'react-router-redux';
|
import { push } from 'react-router-redux';
|
||||||
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
|
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
|
||||||
import NotFound from 'Components/NotFound';
|
import NotFound from 'Components/NotFound';
|
||||||
import SeriesDetailsConnector from './SeriesDetailsConnector';
|
import ArtistDetailsConnector from './ArtistDetailsConnector';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
|
@ -31,7 +31,7 @@ const mapDispatchToProps = {
|
||||||
push
|
push
|
||||||
};
|
};
|
||||||
|
|
||||||
class SeriesDetailsPageConnector extends Component {
|
class ArtistDetailsPageConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
|
@ -60,17 +60,17 @@ class SeriesDetailsPageConnector extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SeriesDetailsConnector
|
<ArtistDetailsConnector
|
||||||
nameSlug={nameSlug}
|
nameSlug={nameSlug}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SeriesDetailsPageConnector.propTypes = {
|
ArtistDetailsPageConnector.propTypes = {
|
||||||
nameSlug: PropTypes.string,
|
nameSlug: PropTypes.string,
|
||||||
match: PropTypes.shape({ params: PropTypes.shape({ nameSlug: PropTypes.string.isRequired }).isRequired }).isRequired,
|
match: PropTypes.shape({ params: PropTypes.shape({ nameSlug: PropTypes.string.isRequired }).isRequired }).isRequired,
|
||||||
push: PropTypes.func.isRequired
|
push: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(SeriesDetailsPageConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistDetailsPageConnector);
|
|
@ -1,4 +1,4 @@
|
||||||
.season {
|
.albumType {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
border: 1px solid $borderColor;
|
border: 1px solid $borderColor;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
@ -17,11 +17,17 @@
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.seasonNumber {
|
.albumTypeLabel {
|
||||||
margin-right: 10px;
|
margin-right: 5px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.albumCount {
|
||||||
|
font-size: 18px;
|
||||||
|
font-style: italic;
|
||||||
|
color: #8895aa;
|
||||||
|
}
|
||||||
|
|
||||||
.episodeCountContainer {
|
.episodeCountContainer {
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
vertical-align: text-bottom;
|
vertical-align: text-bottom;
|
||||||
|
@ -38,7 +44,7 @@
|
||||||
.left {
|
.left {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 0 1 600px;
|
flex: 0 1 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.left,
|
.left,
|
|
@ -7,9 +7,7 @@ import getToggledRange from 'Utilities/Table/getToggledRange';
|
||||||
import { align, icons, kinds, sizes } from 'Helpers/Props';
|
import { align, icons, kinds, sizes } from 'Helpers/Props';
|
||||||
import Icon from 'Components/Icon';
|
import Icon from 'Components/Icon';
|
||||||
import IconButton from 'Components/Link/IconButton';
|
import IconButton from 'Components/Link/IconButton';
|
||||||
import Label from 'Components/Label';
|
|
||||||
import Link from 'Components/Link/Link';
|
import Link from 'Components/Link/Link';
|
||||||
import MonitorToggleButton from 'Components/MonitorToggleButton';
|
|
||||||
import SpinnerIcon from 'Components/SpinnerIcon';
|
import SpinnerIcon from 'Components/SpinnerIcon';
|
||||||
import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
|
import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
|
||||||
import Menu from 'Components/Menu/Menu';
|
import Menu from 'Components/Menu/Menu';
|
||||||
|
@ -20,22 +18,10 @@ import Table from 'Components/Table/Table';
|
||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import EpisodeFileEditorModal from 'EpisodeFile/Editor/EpisodeFileEditorModal';
|
import EpisodeFileEditorModal from 'EpisodeFile/Editor/EpisodeFileEditorModal';
|
||||||
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
|
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
|
||||||
import EpisodeRowConnector from './EpisodeRowConnector';
|
import AlbumRowConnector from './AlbumRowConnector';
|
||||||
import styles from './SeriesDetailsSeason.css';
|
import styles from './ArtistDetailsSeason.css';
|
||||||
|
|
||||||
function getEpisodeCountKind(monitored, episodeFileCount, episodeCount) {
|
class ArtistDetailsSeason extends Component {
|
||||||
if (episodeFileCount === episodeCount && episodeCount > 0) {
|
|
||||||
return kinds.SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!monitored) {
|
|
||||||
return kinds.WARNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
return kinds.DANGER;
|
|
||||||
}
|
|
||||||
|
|
||||||
class SeriesDetailsSeason extends Component {
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
|
@ -65,7 +51,7 @@ class SeriesDetailsSeason extends Component {
|
||||||
|
|
||||||
_expandByDefault() {
|
_expandByDefault() {
|
||||||
const {
|
const {
|
||||||
albumId,
|
name,
|
||||||
onExpandPress,
|
onExpandPress,
|
||||||
items
|
items
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
@ -75,7 +61,7 @@ class SeriesDetailsSeason extends Component {
|
||||||
isAfter(item.airDateUtc, { days: -30 });
|
isAfter(item.airDateUtc, { days: -30 });
|
||||||
});
|
});
|
||||||
|
|
||||||
onExpandPress(albumId, expand && albumId > 0);
|
onExpandPress(name, expand && name > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -99,29 +85,29 @@ class SeriesDetailsSeason extends Component {
|
||||||
|
|
||||||
onExpandPress = () => {
|
onExpandPress = () => {
|
||||||
const {
|
const {
|
||||||
albumId,
|
name,
|
||||||
isExpanded
|
isExpanded
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this.props.onExpandPress(albumId, !isExpanded);
|
this.props.onExpandPress(name, !isExpanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMonitorEpisodePress = (episodeId, monitored, { shiftKey }) => {
|
onMonitorAlbumPress = (albumId, monitored, { shiftKey }) => {
|
||||||
const lastToggled = this.state.lastToggledEpisode;
|
const lastToggled = this.state.lastToggledEpisode;
|
||||||
const episodeIds = [episodeId];
|
const albumIds = [albumId];
|
||||||
|
|
||||||
if (shiftKey && lastToggled) {
|
if (shiftKey && lastToggled) {
|
||||||
const { lower, upper } = getToggledRange(this.props.items, episodeId, lastToggled);
|
const { lower, upper } = getToggledRange(this.props.items, albumId, lastToggled);
|
||||||
const items = this.props.items;
|
const items = this.props.items;
|
||||||
|
|
||||||
for (let i = lower; i < upper; i++) {
|
for (let i = lower; i < upper; i++) {
|
||||||
episodeIds.push(items[i].id);
|
albumIds.push(items[i].id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ lastToggledEpisode: episodeId });
|
this.setState({ lastToggledEpisode: albumId });
|
||||||
|
|
||||||
this.props.onMonitorEpisodePress(_.uniq(episodeIds), monitored);
|
this.props.onMonitorAlbumPress(_.uniq(albumIds), monitored);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -130,29 +116,19 @@ class SeriesDetailsSeason extends Component {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
artistId,
|
artistId,
|
||||||
monitored,
|
label,
|
||||||
title,
|
|
||||||
releaseDate,
|
|
||||||
albumId,
|
|
||||||
statistics,
|
|
||||||
items,
|
items,
|
||||||
columns,
|
columns,
|
||||||
isSaving,
|
isSaving,
|
||||||
isExpanded,
|
isExpanded,
|
||||||
isSearching,
|
isSearching,
|
||||||
seriesMonitored,
|
artistMonitored,
|
||||||
isSmallScreen,
|
isSmallScreen,
|
||||||
onTableOptionChange,
|
onTableOptionChange,
|
||||||
onMonitorSeasonPress,
|
onMonitorSeasonPress,
|
||||||
onSearchPress
|
onSearchPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
|
||||||
trackCount,
|
|
||||||
trackFileCount,
|
|
||||||
totalTrackCount
|
|
||||||
} = statistics;
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isOrganizeModalOpen,
|
isOrganizeModalOpen,
|
||||||
isManageEpisodesOpen
|
isManageEpisodesOpen
|
||||||
|
@ -160,37 +136,22 @@ class SeriesDetailsSeason extends Component {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.season}
|
className={styles.albumType}
|
||||||
>
|
>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<div className={styles.left}>
|
<div className={styles.left}>
|
||||||
<MonitorToggleButton
|
|
||||||
monitored={monitored}
|
|
||||||
isDisabled={!seriesMonitored}
|
|
||||||
isSaving={isSaving}
|
|
||||||
size={24}
|
|
||||||
onPress={onMonitorSeasonPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{
|
{
|
||||||
albumId === 0 ?
|
<div>
|
||||||
<span className={styles.seasonNumber}>
|
<span className={styles.albumTypeLabel}>
|
||||||
Specials
|
{label}
|
||||||
</span> :
|
|
||||||
<span className={styles.seasonNumber}>
|
|
||||||
{title}
|
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span className={styles.albumCount}>
|
||||||
|
({items.length} Releases)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<Label
|
|
||||||
title={`${totalTrackCount} tracks total. ${trackFileCount} tracks with files.`}
|
|
||||||
kind={getEpisodeCountKind(monitored, trackFileCount, trackCount)}
|
|
||||||
size={sizes.LARGE}
|
|
||||||
>
|
|
||||||
{
|
|
||||||
<span>{trackFileCount} / {trackCount}</span>
|
|
||||||
}
|
|
||||||
</Label>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
|
@ -198,6 +159,13 @@ class SeriesDetailsSeason extends Component {
|
||||||
onPress={this.onExpandPress}
|
onPress={this.onExpandPress}
|
||||||
>
|
>
|
||||||
|
|
||||||
|
<Icon
|
||||||
|
className={styles.expandButtonIcon}
|
||||||
|
name={isExpanded ? icons.COLLAPSE : icons.EXPAND}
|
||||||
|
title={isExpanded ? 'Hide albums' : 'Show albums'}
|
||||||
|
size={24}
|
||||||
|
/>
|
||||||
|
|
||||||
{
|
{
|
||||||
!isSmallScreen &&
|
!isSmallScreen &&
|
||||||
<span> </span>
|
<span> </span>
|
||||||
|
@ -266,37 +234,62 @@ class SeriesDetailsSeason extends Component {
|
||||||
onPress={onSearchPress}
|
onPress={onSearchPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IconButton
|
|
||||||
className={styles.actionButton}
|
|
||||||
name={icons.ORGANIZE}
|
|
||||||
title="Preview rename for this album"
|
|
||||||
size={24}
|
|
||||||
onPress={this.onOrganizePress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<IconButton
|
|
||||||
className={styles.actionButton}
|
|
||||||
name={icons.EPISODE_FILE}
|
|
||||||
title="Manage track files in this artist"
|
|
||||||
size={24}
|
|
||||||
onPress={this.onManageEpisodesPress}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
isExpanded &&
|
||||||
|
<div className={styles.episodes}>
|
||||||
|
{
|
||||||
|
items.length ?
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
onTableOptionChange={onTableOptionChange}
|
||||||
|
>
|
||||||
|
<TableBody>
|
||||||
|
{
|
||||||
|
items.map((item) => {
|
||||||
|
return (
|
||||||
|
<AlbumRowConnector
|
||||||
|
key={item.id}
|
||||||
|
columns={columns}
|
||||||
|
{...item}
|
||||||
|
onMonitorAlbumPress={this.onMonitorAlbumPress}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</TableBody>
|
||||||
|
</Table> :
|
||||||
|
|
||||||
|
<div className={styles.noEpisodes}>
|
||||||
|
No albums in this group
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div className={styles.collapseButtonContainer}>
|
||||||
|
<IconButton
|
||||||
|
name={icons.COLLAPSE}
|
||||||
|
size={20}
|
||||||
|
title="Hide episodes"
|
||||||
|
onPress={this.onExpandPress}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<OrganizePreviewModalConnector
|
<OrganizePreviewModalConnector
|
||||||
isOpen={isOrganizeModalOpen}
|
isOpen={isOrganizeModalOpen}
|
||||||
artistId={artistId}
|
artistId={artistId}
|
||||||
albumId={albumId}
|
|
||||||
onModalClose={this.onOrganizeModalClose}
|
onModalClose={this.onOrganizeModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EpisodeFileEditorModal
|
<EpisodeFileEditorModal
|
||||||
isOpen={isManageEpisodesOpen}
|
isOpen={isManageEpisodesOpen}
|
||||||
artistId={artistId}
|
artistId={artistId}
|
||||||
albumId={albumId}
|
|
||||||
onModalClose={this.onManageEpisodesModalClose}
|
onModalClose={this.onManageEpisodesModalClose}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -304,33 +297,22 @@ class SeriesDetailsSeason extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SeriesDetailsSeason.propTypes = {
|
ArtistDetailsSeason.propTypes = {
|
||||||
artistId: PropTypes.number.isRequired,
|
artistId: PropTypes.number.isRequired,
|
||||||
monitored: PropTypes.bool.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
title: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
releaseDate: PropTypes.string.isRequired,
|
|
||||||
albumId: PropTypes.number.isRequired,
|
|
||||||
statistics: PropTypes.object.isRequired,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
isSaving: PropTypes.bool,
|
isSaving: PropTypes.bool,
|
||||||
isExpanded: PropTypes.bool,
|
isExpanded: PropTypes.bool,
|
||||||
isSearching: PropTypes.bool.isRequired,
|
isSearching: PropTypes.bool.isRequired,
|
||||||
seriesMonitored: PropTypes.bool.isRequired,
|
artistMonitored: PropTypes.bool.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
onTableOptionChange: PropTypes.func.isRequired,
|
onTableOptionChange: PropTypes.func.isRequired,
|
||||||
onMonitorSeasonPress: PropTypes.func.isRequired,
|
onMonitorSeasonPress: PropTypes.func.isRequired,
|
||||||
onExpandPress: PropTypes.func.isRequired,
|
onExpandPress: PropTypes.func.isRequired,
|
||||||
onMonitorEpisodePress: PropTypes.func.isRequired,
|
onMonitorAlbumPress: PropTypes.func.isRequired,
|
||||||
onSearchPress: PropTypes.func.isRequired
|
onSearchPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
SeriesDetailsSeason.defaultProps = {
|
export default ArtistDetailsSeason;
|
||||||
statistics: {
|
|
||||||
trackFileCount: 0,
|
|
||||||
totalTrackCount: 0,
|
|
||||||
percentOfTracks: 0
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SeriesDetailsSeason;
|
|
|
@ -11,30 +11,30 @@ import { toggleSeasonMonitored } from 'Store/Actions/artistActions';
|
||||||
import { toggleEpisodesMonitored, setEpisodesTableOption } from 'Store/Actions/episodeActions';
|
import { toggleEpisodesMonitored, setEpisodesTableOption } from 'Store/Actions/episodeActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import SeriesDetailsSeason from './SeriesDetailsSeason';
|
import ArtistDetailsSeason from './ArtistDetailsSeason';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { seasonNumber }) => seasonNumber,
|
(state, { label }) => label,
|
||||||
(state) => state.episodes,
|
(state) => state.episodes,
|
||||||
createArtistSelector(),
|
createArtistSelector(),
|
||||||
createCommandsSelector(),
|
createCommandsSelector(),
|
||||||
createDimensionsSelector(),
|
createDimensionsSelector(),
|
||||||
(seasonNumber, episodes, series, commands, dimensions) => {
|
(label, episodes, series, commands, dimensions) => {
|
||||||
const isSearching = !!findCommand(commands, {
|
const isSearching = !!findCommand(commands, {
|
||||||
name: commandNames.SEASON_SEARCH,
|
name: commandNames.SEASON_SEARCH,
|
||||||
artistId: series.id,
|
artistId: series.id,
|
||||||
seasonNumber
|
label
|
||||||
});
|
});
|
||||||
|
|
||||||
const episodesInSeason = _.filter(episodes.items, { seasonNumber });
|
const episodesInSeason = _.filter(episodes.items, { albumType: label });
|
||||||
const sortedEpisodes = _.orderBy(episodesInSeason, 'episodeNumber', 'desc');
|
const sortedEpisodes = _.orderBy(episodesInSeason, 'releaseDate', 'desc');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: sortedEpisodes,
|
items: sortedEpisodes,
|
||||||
columns: episodes.columns,
|
columns: episodes.columns,
|
||||||
isSearching,
|
isSearching,
|
||||||
seriesMonitored: series.monitored,
|
artistMonitored: series.monitored,
|
||||||
isSmallScreen: dimensions.isSmallScreen
|
isSmallScreen: dimensions.isSmallScreen
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ const mapDispatchToProps = {
|
||||||
executeCommand
|
executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class SeriesDetailsSeasonConnector extends Component {
|
class ArtistDetailsSeasonConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
@ -59,33 +59,29 @@ class SeriesDetailsSeasonConnector extends Component {
|
||||||
|
|
||||||
onMonitorSeasonPress = (monitored) => {
|
onMonitorSeasonPress = (monitored) => {
|
||||||
const {
|
const {
|
||||||
artistId,
|
artistId
|
||||||
albumId
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this.props.toggleSeasonMonitored({
|
this.props.toggleSeasonMonitored({
|
||||||
artistId,
|
artistId,
|
||||||
albumId,
|
|
||||||
monitored
|
monitored
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchPress = () => {
|
onSearchPress = () => {
|
||||||
const {
|
const {
|
||||||
artistId,
|
artistId
|
||||||
albumId
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.SEASON_SEARCH,
|
name: commandNames.SEASON_SEARCH,
|
||||||
artistId,
|
artistId
|
||||||
albumIds: [albumId]
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMonitorEpisodePress = (episodeIds, monitored) => {
|
onMonitorAlbumPress = (albumIds, monitored) => {
|
||||||
this.props.toggleEpisodesMonitored({
|
this.props.toggleEpisodesMonitored({
|
||||||
episodeIds,
|
albumIds,
|
||||||
monitored
|
monitored
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -95,24 +91,23 @@ class SeriesDetailsSeasonConnector extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<SeriesDetailsSeason
|
<ArtistDetailsSeason
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onTableOptionChange={this.onTableOptionChange}
|
onTableOptionChange={this.onTableOptionChange}
|
||||||
onMonitorSeasonPress={this.onMonitorSeasonPress}
|
onMonitorSeasonPress={this.onMonitorSeasonPress}
|
||||||
onSearchPress={this.onSearchPress}
|
onSearchPress={this.onSearchPress}
|
||||||
onMonitorEpisodePress={this.onMonitorEpisodePress}
|
onMonitorAlbumPress={this.onMonitorAlbumPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SeriesDetailsSeasonConnector.propTypes = {
|
ArtistDetailsSeasonConnector.propTypes = {
|
||||||
artistId: PropTypes.number.isRequired,
|
artistId: PropTypes.number.isRequired,
|
||||||
albumId: PropTypes.number.isRequired,
|
|
||||||
toggleSeasonMonitored: PropTypes.func.isRequired,
|
toggleSeasonMonitored: PropTypes.func.isRequired,
|
||||||
toggleEpisodesMonitored: PropTypes.func.isRequired,
|
toggleEpisodesMonitored: PropTypes.func.isRequired,
|
||||||
setEpisodesTableOption: PropTypes.func.isRequired,
|
setEpisodesTableOption: PropTypes.func.isRequired,
|
||||||
executeCommand: PropTypes.func.isRequired
|
executeCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(SeriesDetailsSeasonConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistDetailsSeasonConnector);
|
|
@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { kinds, sizes } from 'Helpers/Props';
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
import Label from 'Components/Label';
|
import Label from 'Components/Label';
|
||||||
import styles from './SeriesTags.css';
|
import styles from './ArtistTags.css';
|
||||||
|
|
||||||
function SeriesTags({ tags }) {
|
function ArtistTags({ tags }) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
|
@ -24,8 +24,8 @@ function SeriesTags({ tags }) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
SeriesTags.propTypes = {
|
ArtistTags.propTypes = {
|
||||||
tags: PropTypes.arrayOf(PropTypes.string).isRequired
|
tags: PropTypes.arrayOf(PropTypes.string).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SeriesTags;
|
export default ArtistTags;
|
|
@ -3,7 +3,7 @@ import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
||||||
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
||||||
import SeriesTags from './SeriesTags';
|
import ArtistTags from './ArtistTags';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
|
@ -27,4 +27,4 @@ function createMapStateToProps() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(createMapStateToProps)(SeriesTags);
|
export default connect(createMapStateToProps)(ArtistTags);
|
|
@ -1,266 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import MonitorToggleButton from 'Components/MonitorToggleButton';
|
|
||||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
|
||||||
import TableRow from 'Components/Table/TableRow';
|
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
|
||||||
import EpisodeSearchCellConnector from 'Episode/EpisodeSearchCellConnector';
|
|
||||||
import EpisodeNumber from 'Episode/EpisodeNumber';
|
|
||||||
import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
|
|
||||||
import EpisodeStatusConnector from 'Episode/EpisodeStatusConnector';
|
|
||||||
import EpisodeFileLanguageConnector from 'EpisodeFile/EpisodeFileLanguageConnector';
|
|
||||||
import MediaInfoConnector from 'EpisodeFile/MediaInfoConnector';
|
|
||||||
import * as mediaInfoTypes from 'EpisodeFile/mediaInfoTypes';
|
|
||||||
|
|
||||||
import styles from './EpisodeRow.css';
|
|
||||||
|
|
||||||
class EpisodeRow extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isDetailsModalOpen: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onManualSearchPress = () => {
|
|
||||||
this.setState({ isDetailsModalOpen: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
onDetailsModalClose = () => {
|
|
||||||
this.setState({ isDetailsModalOpen: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
onMonitorEpisodePress = (monitored, options) => {
|
|
||||||
this.props.onMonitorEpisodePress(this.props.id, monitored, options);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
artistId,
|
|
||||||
episodeFileId,
|
|
||||||
monitored,
|
|
||||||
seasonNumber,
|
|
||||||
episodeNumber,
|
|
||||||
absoluteEpisodeNumber,
|
|
||||||
sceneSeasonNumber,
|
|
||||||
sceneEpisodeNumber,
|
|
||||||
sceneAbsoluteEpisodeNumber,
|
|
||||||
airDateUtc,
|
|
||||||
title,
|
|
||||||
unverifiedSceneNumbering,
|
|
||||||
isSaving,
|
|
||||||
seriesMonitored,
|
|
||||||
seriesType,
|
|
||||||
episodeFilePath,
|
|
||||||
episodeFileRelativePath,
|
|
||||||
alternateTitles,
|
|
||||||
columns
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TableRow>
|
|
||||||
{
|
|
||||||
columns.map((column) => {
|
|
||||||
const {
|
|
||||||
name,
|
|
||||||
isVisible
|
|
||||||
} = column;
|
|
||||||
|
|
||||||
if (!isVisible) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'monitored') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.monitored}
|
|
||||||
>
|
|
||||||
<MonitorToggleButton
|
|
||||||
monitored={monitored}
|
|
||||||
isDisabled={!seriesMonitored}
|
|
||||||
isSaving={isSaving}
|
|
||||||
onPress={this.onMonitorEpisodePress}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'episodeNumber') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.episodeNumber}
|
|
||||||
>
|
|
||||||
<EpisodeNumber
|
|
||||||
seasonNumber={seasonNumber}
|
|
||||||
episodeNumber={episodeNumber}
|
|
||||||
absoluteEpisodeNumber={absoluteEpisodeNumber}
|
|
||||||
unverifiedSceneNumbering={unverifiedSceneNumbering}
|
|
||||||
seriesType={seriesType}
|
|
||||||
sceneSeasonNumber={sceneSeasonNumber}
|
|
||||||
sceneEpisodeNumber={sceneEpisodeNumber}
|
|
||||||
sceneAbsoluteEpisodeNumber={sceneAbsoluteEpisodeNumber}
|
|
||||||
alternateTitles={alternateTitles}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'title') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.title}
|
|
||||||
>
|
|
||||||
<EpisodeTitleLink
|
|
||||||
episodeId={id}
|
|
||||||
artistId={artistId}
|
|
||||||
episodeTitle={title}
|
|
||||||
showOpenSeriesButton={false}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'path') {
|
|
||||||
return (
|
|
||||||
<TableRowCell key={name}>
|
|
||||||
{
|
|
||||||
episodeFilePath
|
|
||||||
}
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'relativePath') {
|
|
||||||
return (
|
|
||||||
<TableRowCell key={name}>
|
|
||||||
{
|
|
||||||
episodeFileRelativePath
|
|
||||||
}
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'airDateUtc') {
|
|
||||||
return (
|
|
||||||
<RelativeDateCellConnector
|
|
||||||
key={name}
|
|
||||||
date={airDateUtc}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'language') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.language}
|
|
||||||
>
|
|
||||||
<EpisodeFileLanguageConnector
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'audioInfo') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.audio}
|
|
||||||
>
|
|
||||||
<MediaInfoConnector
|
|
||||||
type={mediaInfoTypes.AUDIO}
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'videoCodec') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.video}
|
|
||||||
>
|
|
||||||
<MediaInfoConnector
|
|
||||||
type={mediaInfoTypes.VIDEO}
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'status') {
|
|
||||||
return (
|
|
||||||
<TableRowCell
|
|
||||||
key={name}
|
|
||||||
className={styles.status}
|
|
||||||
>
|
|
||||||
<EpisodeStatusConnector
|
|
||||||
episodeId={id}
|
|
||||||
episodeFileId={episodeFileId}
|
|
||||||
/>
|
|
||||||
</TableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name === 'actions') {
|
|
||||||
return (
|
|
||||||
<EpisodeSearchCellConnector
|
|
||||||
key={name}
|
|
||||||
episodeId={id}
|
|
||||||
artistId={artistId}
|
|
||||||
episodeTitle={title}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</TableRow>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EpisodeRow.propTypes = {
|
|
||||||
id: PropTypes.number.isRequired,
|
|
||||||
artistId: PropTypes.number.isRequired,
|
|
||||||
episodeFileId: PropTypes.number,
|
|
||||||
monitored: PropTypes.bool.isRequired,
|
|
||||||
seasonNumber: PropTypes.number.isRequired,
|
|
||||||
episodeNumber: PropTypes.number.isRequired,
|
|
||||||
absoluteEpisodeNumber: PropTypes.number,
|
|
||||||
sceneSeasonNumber: PropTypes.number,
|
|
||||||
sceneEpisodeNumber: PropTypes.number,
|
|
||||||
sceneAbsoluteEpisodeNumber: PropTypes.number,
|
|
||||||
airDateUtc: PropTypes.string,
|
|
||||||
title: PropTypes.string.isRequired,
|
|
||||||
isSaving: PropTypes.bool,
|
|
||||||
unverifiedSceneNumbering: PropTypes.bool,
|
|
||||||
seriesMonitored: PropTypes.bool.isRequired,
|
|
||||||
seriesType: PropTypes.string.isRequired,
|
|
||||||
episodeFilePath: PropTypes.string,
|
|
||||||
episodeFileRelativePath: PropTypes.string,
|
|
||||||
mediaInfo: PropTypes.object,
|
|
||||||
alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
onMonitorEpisodePress: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default EpisodeRow;
|
|
|
@ -1,70 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import { kinds, sizes } from 'Helpers/Props';
|
|
||||||
import Label from 'Components/Label';
|
|
||||||
import Link from 'Components/Link/Link';
|
|
||||||
import styles from './SeriesDetailsLinks.css';
|
|
||||||
|
|
||||||
function SeriesDetailsLinks(props) {
|
|
||||||
const {
|
|
||||||
foreignArtistId,
|
|
||||||
tvMazeId,
|
|
||||||
imdbId
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={styles.links}>
|
|
||||||
<Link
|
|
||||||
className={styles.link}
|
|
||||||
to={`https://musicbrainz.org/artist/${foreignArtistId}`}
|
|
||||||
>
|
|
||||||
<Label
|
|
||||||
className={styles.linkLabel}
|
|
||||||
kind={kinds.INFO}
|
|
||||||
size={sizes.LARGE}
|
|
||||||
>
|
|
||||||
Musicbrainz
|
|
||||||
</Label>
|
|
||||||
</Link>
|
|
||||||
{
|
|
||||||
!!tvMazeId &&
|
|
||||||
<Link
|
|
||||||
className={styles.link}
|
|
||||||
to={`http://www.tvmaze.com/shows/${tvMazeId}/_`}
|
|
||||||
>
|
|
||||||
<Label
|
|
||||||
className={styles.linkLabel}
|
|
||||||
kind={kinds.INFO}
|
|
||||||
size={sizes.LARGE}
|
|
||||||
>
|
|
||||||
TV Maze
|
|
||||||
</Label>
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
!!imdbId &&
|
|
||||||
<Link
|
|
||||||
className={styles.link}
|
|
||||||
to={`http://imdb.com/title/${imdbId}/`}
|
|
||||||
>
|
|
||||||
<Label
|
|
||||||
className={styles.linkLabel}
|
|
||||||
kind={kinds.INFO}
|
|
||||||
size={sizes.LARGE}
|
|
||||||
>
|
|
||||||
IMDB
|
|
||||||
</Label>
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
SeriesDetailsLinks.propTypes = {
|
|
||||||
foreignArtistId: PropTypes.string.isRequired,
|
|
||||||
tvMazeId: PropTypes.number,
|
|
||||||
imdbId: PropTypes.string
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SeriesDetailsLinks;
|
|
|
@ -27,7 +27,7 @@ function ArtistStatusCell(props) {
|
||||||
|
|
||||||
<Icon
|
<Icon
|
||||||
className={styles.statusIcon}
|
className={styles.statusIcon}
|
||||||
name={status === 'ended' ? icons.SERIES_ENDED : icons.SERIES_CONTINUING}
|
name={status === 'ended' ? icons.ARTIST_ENDED : icons.ARTIST_CONTINUING}
|
||||||
title={status === 'ended' ? 'Ended' : 'Continuing'}
|
title={status === 'ended' ? 'Ended' : 'Continuing'}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -7,9 +7,9 @@ export const CUTOFF_UNMET_EPISODE_SEARCH = 'CutoffUnmetEpisodeSearch';
|
||||||
export const DELETE_LOG_FILES = 'DeleteLogFiles';
|
export const DELETE_LOG_FILES = 'DeleteLogFiles';
|
||||||
export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles';
|
export const DELETE_UPDATE_LOG_FILES = 'DeleteUpdateLogFiles';
|
||||||
export const DOWNLOADED_EPSIODES_SCAN = 'DownloadedEpisodesScan';
|
export const DOWNLOADED_EPSIODES_SCAN = 'DownloadedEpisodesScan';
|
||||||
export const EPISODE_SEARCH = 'EpisodeSearch';
|
export const EPISODE_SEARCH = 'AlbumSearch';
|
||||||
export const INTERACTIVE_IMPORT = 'ManualImport';
|
export const INTERACTIVE_IMPORT = 'ManualImport';
|
||||||
export const MISSING_EPISODE_SEARCH = 'MissingEpisodeSearch';
|
export const MISSING_ALBUM_SEARCH = 'MissingAlbumSearch';
|
||||||
export const REFRESH_ARTIST = 'RefreshArtist';
|
export const REFRESH_ARTIST = 'RefreshArtist';
|
||||||
export const RENAME_FILES = 'RenameFiles';
|
export const RENAME_FILES = 'RenameFiles';
|
||||||
export const RENAME_ARTIST = 'RenameArtist';
|
export const RENAME_ARTIST = 'RenameArtist';
|
||||||
|
|
|
@ -19,7 +19,7 @@ const SIDEBAR_WIDTH = parseInt(dimensions.sidebarWidth);
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
{
|
{
|
||||||
iconName: icons.SERIES_CONTINUING,
|
iconName: icons.ARTIST_CONTINUING,
|
||||||
title: 'Artist',
|
title: 'Artist',
|
||||||
to: '/',
|
to: '/',
|
||||||
alias: '/series',
|
alias: '/series',
|
||||||
|
|
|
@ -11,7 +11,6 @@ import MonitorToggleButton from 'Components/MonitorToggleButton';
|
||||||
import EpisodeSummaryConnector from './Summary/EpisodeSummaryConnector';
|
import EpisodeSummaryConnector from './Summary/EpisodeSummaryConnector';
|
||||||
import EpisodeHistoryConnector from './History/EpisodeHistoryConnector';
|
import EpisodeHistoryConnector from './History/EpisodeHistoryConnector';
|
||||||
import EpisodeSearchConnector from './Search/EpisodeSearchConnector';
|
import EpisodeSearchConnector from './Search/EpisodeSearchConnector';
|
||||||
import SeasonEpisodeNumber from './SeasonEpisodeNumber';
|
|
||||||
import styles from './EpisodeDetailsModalContent.css';
|
import styles from './EpisodeDetailsModalContent.css';
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
|
@ -47,26 +46,22 @@ class EpisodeDetailsModalContent extends Component {
|
||||||
const {
|
const {
|
||||||
episodeId,
|
episodeId,
|
||||||
episodeEntity,
|
episodeEntity,
|
||||||
episodeFileId,
|
|
||||||
artistId,
|
artistId,
|
||||||
seriesTitle,
|
seriesTitle,
|
||||||
titleSlug,
|
nameSlug,
|
||||||
seriesMonitored,
|
albumLabel,
|
||||||
seriesType,
|
artistMonitored,
|
||||||
seasonNumber,
|
|
||||||
episodeNumber,
|
|
||||||
absoluteEpisodeNumber,
|
|
||||||
episodeTitle,
|
episodeTitle,
|
||||||
airDate,
|
releaseDate,
|
||||||
monitored,
|
monitored,
|
||||||
isSaving,
|
isSaving,
|
||||||
showOpenSeriesButton,
|
showOpenSeriesButton,
|
||||||
startInteractiveSearch,
|
startInteractiveSearch,
|
||||||
onMonitorEpisodePress,
|
onMonitorAlbumPress,
|
||||||
onModalClose
|
onModalClose
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const seriesLink = `/artist/${titleSlug}`;
|
const seriesLink = `/artist/${nameSlug}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalContent
|
<ModalContent
|
||||||
|
@ -78,9 +73,9 @@ class EpisodeDetailsModalContent extends Component {
|
||||||
id={episodeId}
|
id={episodeId}
|
||||||
monitored={monitored}
|
monitored={monitored}
|
||||||
size={18}
|
size={18}
|
||||||
isDisabled={!seriesMonitored}
|
isDisabled={!artistMonitored}
|
||||||
isSaving={isSaving}
|
isSaving={isSaving}
|
||||||
onPress={onMonitorEpisodePress}
|
onPress={onMonitorAlbumPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<span className={styles.seriesTitle}>
|
<span className={styles.seriesTitle}>
|
||||||
|
@ -89,16 +84,6 @@ class EpisodeDetailsModalContent extends Component {
|
||||||
|
|
||||||
<span className={styles.separator}>-</span>
|
<span className={styles.separator}>-</span>
|
||||||
|
|
||||||
<SeasonEpisodeNumber
|
|
||||||
seasonNumber={seasonNumber}
|
|
||||||
episodeNumber={episodeNumber}
|
|
||||||
absoluteEpisodeNumber={absoluteEpisodeNumber}
|
|
||||||
airDate={airDate}
|
|
||||||
seriesType={seriesType}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<span className={styles.separator}>-</span>
|
|
||||||
|
|
||||||
{episodeTitle}
|
{episodeTitle}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
|
@ -137,7 +122,8 @@ class EpisodeDetailsModalContent extends Component {
|
||||||
<EpisodeSummaryConnector
|
<EpisodeSummaryConnector
|
||||||
episodeId={episodeId}
|
episodeId={episodeId}
|
||||||
episodeEntity={episodeEntity}
|
episodeEntity={episodeEntity}
|
||||||
episodeFileId={episodeFileId}
|
releaseDate={releaseDate}
|
||||||
|
albumLabel={albumLabel}
|
||||||
artistId={artistId}
|
artistId={artistId}
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
@ -150,7 +136,7 @@ class EpisodeDetailsModalContent extends Component {
|
||||||
|
|
||||||
<TabPanel className={styles.tabPanel}>
|
<TabPanel className={styles.tabPanel}>
|
||||||
<EpisodeSearchConnector
|
<EpisodeSearchConnector
|
||||||
episodeId={episodeId}
|
albumId={episodeId}
|
||||||
startInteractiveSearch={startInteractiveSearch}
|
startInteractiveSearch={startInteractiveSearch}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
/>
|
/>
|
||||||
|
@ -166,7 +152,7 @@ class EpisodeDetailsModalContent extends Component {
|
||||||
to={seriesLink}
|
to={seriesLink}
|
||||||
onPress={onModalClose}
|
onPress={onModalClose}
|
||||||
>
|
>
|
||||||
Open Series
|
Open Artist
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,28 +170,25 @@ class EpisodeDetailsModalContent extends Component {
|
||||||
EpisodeDetailsModalContent.propTypes = {
|
EpisodeDetailsModalContent.propTypes = {
|
||||||
episodeId: PropTypes.number.isRequired,
|
episodeId: PropTypes.number.isRequired,
|
||||||
episodeEntity: PropTypes.string.isRequired,
|
episodeEntity: PropTypes.string.isRequired,
|
||||||
episodeFileId: PropTypes.number,
|
|
||||||
artistId: PropTypes.number.isRequired,
|
artistId: PropTypes.number.isRequired,
|
||||||
seriesTitle: PropTypes.string.isRequired,
|
seriesTitle: PropTypes.string.isRequired,
|
||||||
titleSlug: PropTypes.string.isRequired,
|
nameSlug: PropTypes.string.isRequired,
|
||||||
seriesMonitored: PropTypes.bool.isRequired,
|
artistMonitored: PropTypes.bool.isRequired,
|
||||||
seriesType: PropTypes.string.isRequired,
|
releaseDate: PropTypes.string.isRequired,
|
||||||
seasonNumber: PropTypes.number.isRequired,
|
albumLabel: PropTypes.string.isRequired,
|
||||||
episodeNumber: PropTypes.number.isRequired,
|
|
||||||
absoluteEpisodeNumber: PropTypes.number,
|
|
||||||
airDate: PropTypes.string.isRequired,
|
|
||||||
episodeTitle: PropTypes.string.isRequired,
|
episodeTitle: PropTypes.string.isRequired,
|
||||||
monitored: PropTypes.bool.isRequired,
|
monitored: PropTypes.bool.isRequired,
|
||||||
isSaving: PropTypes.bool,
|
isSaving: PropTypes.bool,
|
||||||
showOpenSeriesButton: PropTypes.bool,
|
showOpenSeriesButton: PropTypes.bool,
|
||||||
selectedTab: PropTypes.string.isRequired,
|
selectedTab: PropTypes.string.isRequired,
|
||||||
startInteractiveSearch: PropTypes.bool.isRequired,
|
startInteractiveSearch: PropTypes.bool.isRequired,
|
||||||
onMonitorEpisodePress: PropTypes.func.isRequired,
|
onMonitorAlbumPress: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
EpisodeDetailsModalContent.defaultProps = {
|
EpisodeDetailsModalContent.defaultProps = {
|
||||||
selectedTab: 'details',
|
selectedTab: 'details',
|
||||||
|
albumLabel: 'Unknown',
|
||||||
episodeEntity: episodeEntities.EPISODES,
|
episodeEntity: episodeEntities.EPISODES,
|
||||||
startInteractiveSearch: false
|
startInteractiveSearch: false
|
||||||
};
|
};
|
||||||
|
|
|
@ -15,16 +15,16 @@ function createMapStateToProps() {
|
||||||
createArtistSelector(),
|
createArtistSelector(),
|
||||||
(episode, series) => {
|
(episode, series) => {
|
||||||
const {
|
const {
|
||||||
title: seriesTitle,
|
artistName: seriesTitle,
|
||||||
titleSlug,
|
nameSlug,
|
||||||
monitored: seriesMonitored,
|
monitored: artistMonitored,
|
||||||
seriesType
|
seriesType
|
||||||
} = series;
|
} = series;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
seriesTitle,
|
seriesTitle,
|
||||||
titleSlug,
|
nameSlug,
|
||||||
seriesMonitored,
|
artistMonitored,
|
||||||
seriesType,
|
seriesType,
|
||||||
...episode
|
...episode
|
||||||
};
|
};
|
||||||
|
@ -52,7 +52,7 @@ class EpisodeDetailsModalContentConnector extends Component {
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onMonitorEpisodePress = (monitored) => {
|
onMonitorAlbumPress = (monitored) => {
|
||||||
const {
|
const {
|
||||||
episodeId,
|
episodeId,
|
||||||
episodeEntity
|
episodeEntity
|
||||||
|
@ -72,7 +72,7 @@ class EpisodeDetailsModalContentConnector extends Component {
|
||||||
return (
|
return (
|
||||||
<EpisodeDetailsModalContent
|
<EpisodeDetailsModalContent
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onMonitorEpisodePress={this.onMonitorEpisodePress}
|
onMonitorAlbumPress={this.onMonitorAlbumPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,11 +21,11 @@ function createMapStateToProps() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return command.body.episodeIds.indexOf(episodeId) > -1;
|
return command.body.albumIds.indexOf(episodeId) > -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
seriesMonitored: series.monitored,
|
artistMonitored: series.monitored,
|
||||||
seriesType: series.seriesType,
|
seriesType: series.seriesType,
|
||||||
isSearching
|
isSearching
|
||||||
};
|
};
|
||||||
|
@ -38,7 +38,7 @@ function createMapDispatchToProps(dispatch, props) {
|
||||||
onSearchPress(name, path) {
|
onSearchPress(name, path) {
|
||||||
dispatch(executeCommand({
|
dispatch(executeCommand({
|
||||||
name: commandNames.EPISODE_SEARCH,
|
name: commandNames.EPISODE_SEARCH,
|
||||||
episodeIds: [props.episodeId]
|
albumIds: [props.episodeId]
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,13 +61,13 @@ class EpisodeHistory extends Component {
|
||||||
|
|
||||||
if (!isFetching && !!error) {
|
if (!isFetching && !!error) {
|
||||||
return (
|
return (
|
||||||
<div>Unable to load episode history.</div>
|
<div>Unable to load album history.</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPopulated && !hasItems && !error) {
|
if (isPopulated && !hasItems && !error) {
|
||||||
return (
|
return (
|
||||||
<div>No episode history.</div>
|
<div>No album history.</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ class EpisodeSearchConnector extends Component {
|
||||||
onQuickSearchPress = () => {
|
onQuickSearchPress = () => {
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.EPISODE_SEARCH,
|
name: commandNames.EPISODE_SEARCH,
|
||||||
episodeIds: [this.props.episodeId]
|
albumIds: [this.props.albumId]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.props.onModalClose();
|
this.props.onModalClose();
|
||||||
|
@ -80,7 +80,7 @@ class EpisodeSearchConnector extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
EpisodeSearchConnector.propTypes = {
|
EpisodeSearchConnector.propTypes = {
|
||||||
episodeId: PropTypes.number.isRequired,
|
albumId: PropTypes.number.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
startInteractiveSearch: PropTypes.bool.isRequired,
|
startInteractiveSearch: PropTypes.bool.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -34,7 +34,7 @@ class InteractiveEpisodeSearchConnector extends Component {
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const {
|
const {
|
||||||
episodeId,
|
albumId,
|
||||||
isPopulated
|
isPopulated
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ class InteractiveEpisodeSearchConnector extends Component {
|
||||||
|
|
||||||
if (!isPopulated) {
|
if (!isPopulated) {
|
||||||
this.props.fetchReleases({
|
this.props.fetchReleases({
|
||||||
episodeId
|
albumId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ class InteractiveEpisodeSearchConnector extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
InteractiveEpisodeSearchConnector.propTypes = {
|
InteractiveEpisodeSearchConnector.propTypes = {
|
||||||
episodeId: PropTypes.number.isRequired,
|
albumId: PropTypes.number.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
fetchReleases: PropTypes.func.isRequired,
|
fetchReleases: PropTypes.func.isRequired,
|
||||||
setReleasesSort: PropTypes.func.isRequired,
|
setReleasesSort: PropTypes.func.isRequired,
|
||||||
|
|
|
@ -10,8 +10,8 @@ import Label from 'Components/Label';
|
||||||
|
|
||||||
function EpisodeAiring(props) {
|
function EpisodeAiring(props) {
|
||||||
const {
|
const {
|
||||||
airDateUtc,
|
releaseDate,
|
||||||
network,
|
albumLabel,
|
||||||
shortDateFormat,
|
shortDateFormat,
|
||||||
showRelativeDates,
|
showRelativeDates,
|
||||||
timeFormat
|
timeFormat
|
||||||
|
@ -22,11 +22,11 @@ function EpisodeAiring(props) {
|
||||||
kind={kinds.INFO}
|
kind={kinds.INFO}
|
||||||
size={sizes.MEDIUM}
|
size={sizes.MEDIUM}
|
||||||
>
|
>
|
||||||
{network}
|
{albumLabel}
|
||||||
</Label>
|
</Label>
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!airDateUtc) {
|
if (!releaseDate) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
TBA on {networkLabel}
|
TBA on {networkLabel}
|
||||||
|
@ -34,50 +34,48 @@ function EpisodeAiring(props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const time = formatTime(airDateUtc, timeFormat);
|
|
||||||
|
|
||||||
if (!showRelativeDates) {
|
if (!showRelativeDates) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{moment(airDateUtc).format(shortDateFormat)} at {time} on {networkLabel}
|
{moment(releaseDate).format(shortDateFormat)} on {networkLabel}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isToday(airDateUtc)) {
|
if (isToday(releaseDate)) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{time} on {networkLabel}
|
Today on {networkLabel}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTomorrow(airDateUtc)) {
|
if (isTomorrow(releaseDate)) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
Tomorrow at {time} on {networkLabel}
|
Tomorrow on {networkLabel}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInNextWeek(airDateUtc)) {
|
if (isInNextWeek(releaseDate)) {
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{moment(airDateUtc).format('dddd')} at {time} on {networkLabel}
|
{moment(releaseDate).format('dddd')} on {networkLabel}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{moment(airDateUtc).format(shortDateFormat)} at {time} on {networkLabel}
|
{moment(releaseDate).format(shortDateFormat)} on {networkLabel}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
EpisodeAiring.propTypes = {
|
EpisodeAiring.propTypes = {
|
||||||
airDateUtc: PropTypes.string.isRequired,
|
releaseDate: PropTypes.string.isRequired,
|
||||||
network: PropTypes.string.isRequired,
|
albumLabel: PropTypes.string.isRequired,
|
||||||
shortDateFormat: PropTypes.string.isRequired,
|
shortDateFormat: PropTypes.string.isRequired,
|
||||||
showRelativeDates: PropTypes.bool.isRequired,
|
showRelativeDates: PropTypes.bool.isRequired,
|
||||||
timeFormat: PropTypes.string.isRequired
|
timeFormat: PropTypes.string.isRequired
|
||||||
|
|
|
@ -45,9 +45,9 @@ class EpisodeSummary extends Component {
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
network,
|
|
||||||
overview,
|
overview,
|
||||||
airDateUtc,
|
releaseDate,
|
||||||
|
albumLabel,
|
||||||
path,
|
path,
|
||||||
size,
|
size,
|
||||||
quality,
|
quality,
|
||||||
|
@ -59,11 +59,11 @@ class EpisodeSummary extends Component {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<span className={styles.infoTitle}>Airs</span>
|
<span className={styles.infoTitle}>Releases</span>
|
||||||
|
|
||||||
<EpisodeAiringConnector
|
<EpisodeAiringConnector
|
||||||
airDateUtc={airDateUtc}
|
releaseDate={releaseDate}
|
||||||
network={network}
|
albumLabel={albumLabel}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ class EpisodeSummary extends Component {
|
||||||
{
|
{
|
||||||
hasOverview ?
|
hasOverview ?
|
||||||
overview :
|
overview :
|
||||||
'No episode overview.'
|
'No album overview.'
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -151,11 +151,10 @@ class EpisodeSummary extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
EpisodeSummary.propTypes = {
|
EpisodeSummary.propTypes = {
|
||||||
episodeFileId: PropTypes.number.isRequired,
|
|
||||||
qualityProfileId: PropTypes.number.isRequired,
|
qualityProfileId: PropTypes.number.isRequired,
|
||||||
network: PropTypes.string.isRequired,
|
|
||||||
overview: PropTypes.string,
|
overview: PropTypes.string,
|
||||||
airDateUtc: PropTypes.string.isRequired,
|
albumLabel: PropTypes.string,
|
||||||
|
releaseDate: PropTypes.string.isRequired,
|
||||||
path: PropTypes.string,
|
path: PropTypes.string,
|
||||||
size: PropTypes.number,
|
size: PropTypes.number,
|
||||||
quality: PropTypes.object,
|
quality: PropTypes.object,
|
||||||
|
|
|
@ -67,8 +67,8 @@ export const RSS = 'fa fa-rss';
|
||||||
export const SAVE = 'fa fa-floppy-o';
|
export const SAVE = 'fa fa-floppy-o';
|
||||||
export const SCHEDULED = 'fa fa-clock-o';
|
export const SCHEDULED = 'fa fa-clock-o';
|
||||||
export const SEARCH = 'fa fa-search';
|
export const SEARCH = 'fa fa-search';
|
||||||
export const SERIES_CONTINUING = 'fa fa-play';
|
export const ARTIST_CONTINUING = 'fa fa-play';
|
||||||
export const SERIES_ENDED = 'fa fa-stop';
|
export const ARTIST_ENDED = 'fa fa-stop';
|
||||||
export const SETTINGS = 'fa fa-cogs';
|
export const SETTINGS = 'fa fa-cogs';
|
||||||
export const SHUTDOWN = 'fa fa-power-off';
|
export const SHUTDOWN = 'fa fa-power-off';
|
||||||
export const SORT = 'fa fa-sort';
|
export const SORT = 'fa fa-sort';
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { updateItem } from './baseActions';
|
||||||
const section = 'episodes';
|
const section = 'episodes';
|
||||||
|
|
||||||
const episodeActionHandlers = {
|
const episodeActionHandlers = {
|
||||||
[types.FETCH_EPISODES]: createFetchHandler(section, '/track'),
|
[types.FETCH_EPISODES]: createFetchHandler(section, '/album'),
|
||||||
|
|
||||||
[types.TOGGLE_EPISODE_MONITORED]: function(payload) {
|
[types.TOGGLE_EPISODE_MONITORED]: function(payload) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
|
@ -28,7 +28,7 @@ const episodeActionHandlers = {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const promise = $.ajax({
|
const promise = $.ajax({
|
||||||
url: `/episode/${id}`,
|
url: `/album/${id}`,
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
data: JSON.stringify({ monitored }),
|
data: JSON.stringify({ monitored }),
|
||||||
dataType: 'json'
|
dataType: 'json'
|
||||||
|
@ -56,7 +56,7 @@ const episodeActionHandlers = {
|
||||||
[types.TOGGLE_EPISODES_MONITORED]: function(payload) {
|
[types.TOGGLE_EPISODES_MONITORED]: function(payload) {
|
||||||
return function(dispatch, getState) {
|
return function(dispatch, getState) {
|
||||||
const {
|
const {
|
||||||
episodeIds,
|
albumIds,
|
||||||
episodeEntity = episodeEntities.EPISODES,
|
episodeEntity = episodeEntities.EPISODES,
|
||||||
monitored
|
monitored
|
||||||
} = payload;
|
} = payload;
|
||||||
|
@ -64,7 +64,7 @@ const episodeActionHandlers = {
|
||||||
const episodeSection = _.last(episodeEntity.split('.'));
|
const episodeSection = _.last(episodeEntity.split('.'));
|
||||||
|
|
||||||
dispatch(batchActions(
|
dispatch(batchActions(
|
||||||
episodeIds.map((episodeId) => {
|
albumIds.map((episodeId) => {
|
||||||
return updateItem({
|
return updateItem({
|
||||||
id: episodeId,
|
id: episodeId,
|
||||||
section: episodeSection,
|
section: episodeSection,
|
||||||
|
@ -74,15 +74,15 @@ const episodeActionHandlers = {
|
||||||
));
|
));
|
||||||
|
|
||||||
const promise = $.ajax({
|
const promise = $.ajax({
|
||||||
url: '/episode/monitor',
|
url: '/album/monitor',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
data: JSON.stringify({ episodeIds, monitored }),
|
data: JSON.stringify({ albumIds, monitored }),
|
||||||
dataType: 'json'
|
dataType: 'json'
|
||||||
});
|
});
|
||||||
|
|
||||||
promise.done((data) => {
|
promise.done((data) => {
|
||||||
dispatch(batchActions(
|
dispatch(batchActions(
|
||||||
episodeIds.map((episodeId) => {
|
albumIds.map((episodeId) => {
|
||||||
return updateItem({
|
return updateItem({
|
||||||
id: episodeId,
|
id: episodeId,
|
||||||
section: episodeSection,
|
section: episodeSection,
|
||||||
|
@ -95,7 +95,7 @@ const episodeActionHandlers = {
|
||||||
|
|
||||||
promise.fail((xhr) => {
|
promise.fail((xhr) => {
|
||||||
dispatch(batchActions(
|
dispatch(batchActions(
|
||||||
episodeIds.map((episodeId) => {
|
albumIds.map((episodeId) => {
|
||||||
return updateItem({
|
return updateItem({
|
||||||
id: episodeId,
|
id: episodeId,
|
||||||
section: episodeSection,
|
section: episodeSection,
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const defaultState = {
|
||||||
isFetching: false,
|
isFetching: false,
|
||||||
isPopulated: false,
|
isPopulated: false,
|
||||||
error: null,
|
error: null,
|
||||||
sortKey: 'episodeNumber',
|
sortKey: 'releaseDate',
|
||||||
sortDirection: sortDirections.DESCENDING,
|
sortDirection: sortDirections.DESCENDING,
|
||||||
items: [],
|
items: [],
|
||||||
|
|
||||||
|
@ -22,11 +22,6 @@ export const defaultState = {
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
isModifiable: false
|
isModifiable: false
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'episodeNumber',
|
|
||||||
label: '#',
|
|
||||||
isVisible: true
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'title',
|
name: 'title',
|
||||||
label: 'Title',
|
label: 'Title',
|
||||||
|
@ -38,28 +33,18 @@ export const defaultState = {
|
||||||
isVisible: false
|
isVisible: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'relativePath',
|
name: 'releaseDate',
|
||||||
label: 'Relative Path',
|
label: 'Release Date',
|
||||||
isVisible: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'airDateUtc',
|
|
||||||
label: 'Air Date',
|
|
||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'language',
|
name: 'trackCount',
|
||||||
label: 'Language',
|
label: 'Track Count',
|
||||||
isVisible: false
|
isVisible: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'audioInfo',
|
name: 'duration',
|
||||||
label: 'Audio Info',
|
label: 'Duration',
|
||||||
isVisible: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'videoCodec',
|
|
||||||
label: 'Video Codec',
|
|
||||||
isVisible: false
|
isVisible: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -110,7 +110,7 @@ class CutoffUnmetConnector extends Component {
|
||||||
onSearchSelectedPress = (selected) => {
|
onSearchSelectedPress = (selected) => {
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.EPISODE_SEARCH,
|
name: commandNames.EPISODE_SEARCH,
|
||||||
episodeIds: selected
|
albumIds: selected
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ function createMapStateToProps() {
|
||||||
createCommandsSelector(),
|
createCommandsSelector(),
|
||||||
(missing, commands) => {
|
(missing, commands) => {
|
||||||
const isSearchingForAlbums = _.some(commands, { name: commandNames.EPISODE_SEARCH });
|
const isSearchingForAlbums = _.some(commands, { name: commandNames.EPISODE_SEARCH });
|
||||||
const isSearchingForMissingAlbums = _.some(commands, { name: commandNames.MISSING_EPISODE_SEARCH });
|
const isSearchingForMissingAlbums = _.some(commands, { name: commandNames.MISSING_ALBUM_SEARCH });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isSearchingForAlbums,
|
isSearchingForAlbums,
|
||||||
|
@ -100,7 +100,7 @@ class MissingConnector extends Component {
|
||||||
onSearchSelectedPress = (selected) => {
|
onSearchSelectedPress = (selected) => {
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.EPISODE_SEARCH,
|
name: commandNames.EPISODE_SEARCH,
|
||||||
episodeIds: selected
|
albumIds: selected
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ class MissingConnector extends Component {
|
||||||
|
|
||||||
onSearchAllMissingPress = () => {
|
onSearchAllMissingPress = () => {
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.MISSING_EPISODE_SEARCH
|
name: commandNames.MISSING_ALBUM_SEARCH
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue