Fixed: Address issues with the status being wrong color on the index and movie details (not tracking anything queued/downloading)

Fixed: Updated fetchQueueDetails() to not pass movie ids since the store doesn't use them anyways
New: Added text to index poster progress bar showing status

#4525
#4526
#4982
pull/4986/head
Austin Best 4 years ago committed by Qstick
parent a2e8d1d5d6
commit c51b08e26c

@ -76,16 +76,15 @@ class CalendarConnector extends Component {
} = this.props;
if (hasDifferentItems(prevProps.items, items)) {
const movieIds = selectUniqueIds(items, 'id');
const movieFileIds = selectUniqueIds(items, 'movieFileId');
if (items.length) {
this.props.fetchQueueDetails({ movieIds });
}
if (movieFileIds.length) {
this.props.fetchMovieFiles({ movieFileIds });
}
if (items.length) {
this.props.fetchQueueDetails();
}
}
if (prevProps.time !== time) {

@ -87,6 +87,15 @@
}
}
.queue {
border-color: $queueColor;
background-color: $queueColor;
&.outline {
color: $queueColor;
}
}
/** Sizes **/
.small {

@ -73,6 +73,10 @@
background-color: $infoColor;
}
.queue {
background-color: $queueColor;
}
.small {
height: $progressBarSmallHeight;

@ -8,6 +8,7 @@ export const PRIMARY = 'primary';
export const PURPLE = 'purple';
export const SUCCESS = 'success';
export const WARNING = 'warning';
export const QUEUE = 'queue';
export const all = [
DANGER,
@ -19,5 +20,6 @@ export const all = [
PRIMARY,
PURPLE,
SUCCESS,
WARNING
WARNING,
QUEUE
];

@ -267,6 +267,7 @@ class MovieDetails extends Component {
onMonitorTogglePress,
onRefreshPress,
onSearchPress,
queueDetails,
movieRuntimeFormat
} = this.props;
@ -505,6 +506,7 @@ class MovieDetails extends Component {
hasMovieFiles={hasMovieFiles}
monitored={monitored}
isAvailable={isAvailable}
queueDetails={queueDetails}
/>
</span>
</InfoLabel>
@ -774,6 +776,7 @@ MovieDetails.propTypes = {
onRefreshPress: PropTypes.func.isRequired,
onSearchPress: PropTypes.func.isRequired,
onGoToMovie: PropTypes.func.isRequired,
queueDetails: PropTypes.object,
movieRuntimeFormat: PropTypes.string.isRequired
};

@ -87,9 +87,10 @@ function createMapStateToProps() {
createAllMoviesSelector(),
createCommandsSelector(),
createDimensionsSelector(),
(state) => state.queue.details,
(state) => state.app.isSidebarVisible,
(state) => state.settings.ui.item.movieRuntimeFormat,
(titleSlug, movieFiles, movieCredits, extraFiles, allMovies, commands, dimensions, isSidebarVisible, movieRuntimeFormat) => {
(titleSlug, movieFiles, movieCredits, extraFiles, allMovies, commands, dimensions, queueDetails, isSidebarVisible, movieRuntimeFormat) => {
const sortedMovies = _.orderBy(allMovies, 'sortTitle');
const movieIndex = _.findIndex(sortedMovies, { titleSlug });
const movie = sortedMovies[movieIndex];
@ -162,6 +163,7 @@ function createMapStateToProps() {
nextMovie,
isSmallScreen: dimensions.isSmallScreen,
isSidebarVisible,
queueDetails,
movieRuntimeFormat
};
}

@ -17,3 +17,8 @@
padding-left: 2px;
border-left: 4px solid $warningColor;
}
.queue {
padding-left: 2px;
border-left: 4px solid $queueColor;
}

@ -1,36 +1,50 @@
import PropTypes from 'prop-types';
import React from 'react';
import getQueueStatusText from 'Utilities/Movie/getQueueStatusText';
import translate from 'Utilities/String/translate';
import styles from './MovieStatusLabel.css';
function getMovieStatus(hasFile, isMonitored, isAvailable) {
function getMovieStatus(hasFile, isMonitored, isAvailable, queueDetails = false) {
if (queueDetails.items[0]) {
const queueStatus = queueDetails.items[0].status;
const queueState = queueDetails.items[0].trackedDownloadStatus;
const queueStatusText = getQueueStatusText(queueStatus, queueState);
return queueStatusText.longText;
}
if (hasFile) {
return 'Downloaded';
return translate('Downloaded');
}
if (!isMonitored) {
return 'Unmonitored';
return translate('Unmonitored');
}
if (isAvailable && !hasFile) {
return 'Missing';
return translate('Missing');
}
return 'Unreleased';
return translate('Unreleased');
}
function MovieStatusLabel(props) {
const {
hasMovieFiles,
monitored,
isAvailable
isAvailable,
queueDetails
} = props;
const status = getMovieStatus(hasMovieFiles, monitored, isAvailable);
const status = getMovieStatus(hasMovieFiles, monitored, isAvailable, queueDetails);
let statusClass = status;
if (queueDetails.items.length) {
statusClass = 'queue';
}
return (
<span
className={styles[status.toLowerCase()]}
className={styles[statusClass]}
>
{status}
</span>
@ -40,7 +54,8 @@ function MovieStatusLabel(props) {
MovieStatusLabel.propTypes = {
hasMovieFiles: PropTypes.bool.isRequired,
monitored: PropTypes.bool.isRequired,
isAvailable: PropTypes.bool.isRequired
isAvailable: PropTypes.bool.isRequired,
queueDetails: PropTypes.object
};
MovieStatusLabel.defaultProps = {

@ -6,6 +6,7 @@ import * as commandNames from 'Commands/commandNames';
import withScrollPosition from 'Components/withScrollPosition';
import { executeCommand } from 'Store/Actions/commandActions';
import { saveMovieEditor, setMovieFilter, setMovieSort, setMovieTableOption, setMovieView } from 'Store/Actions/movieIndexActions';
import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions';
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
import scrollPositions from 'Store/scrollPositions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
@ -45,6 +46,14 @@ function createMapStateToProps() {
function createMapDispatchToProps(dispatch, props) {
return {
fetchQueueDetails() {
dispatch(fetchQueueDetails());
},
clearQueueDetails() {
dispatch(clearQueueDetails());
},
dispatchFetchRootFolders() {
dispatch(fetchRootFolders());
},
@ -96,6 +105,11 @@ class MovieIndexConnector extends Component {
componentDidMount() {
// TODO: Fetch root folders here for now, but should eventually fetch on editor toggle and check loaded before showing controls
this.props.dispatchFetchRootFolders();
this.props.fetchQueueDetails();
}
componentWillUnmount() {
this.props.clearQueueDetails();
}
//
@ -134,7 +148,10 @@ MovieIndexConnector.propTypes = {
view: PropTypes.string.isRequired,
dispatchFetchRootFolders: PropTypes.func.isRequired,
dispatchSetMovieView: PropTypes.func.isRequired,
dispatchSaveMovieEditor: PropTypes.func.isRequired
dispatchSaveMovieEditor: PropTypes.func.isRequired,
fetchQueueDetails: PropTypes.func.isRequired,
clearQueueDetails: PropTypes.func.isRequired,
items: PropTypes.arrayOf(PropTypes.object)
};
export default withScrollPosition(

@ -18,6 +18,12 @@
border-radius: 4px;
}
.queue {
composes: legendItemColor;
background-color: $queueColor;
}
.continuing {
composes: legendItemColor;

@ -26,12 +26,6 @@ class MovieIndexFooter extends PureComponent {
movieFiles += 1;
}
// if (s.status === 'ended') {
// ended++;
// } else {
// continuing++;
// }
if (s.monitored) {
monitored++;
}
@ -78,6 +72,13 @@ class MovieIndexFooter extends PureComponent {
</div>
</div>
<div className={styles.legendItem}>
<div className={styles.queue} />
<div>
{translate('Queued')}
</div>
</div>
<div className={styles.legendItem}>
<div className={styles.continuing} />
<div>

@ -32,11 +32,13 @@ function createMapStateToProps() {
createMovieQualityProfileSelector(),
selectShowSearchAction(),
createExecutingCommandsSelector(),
(state) => state.queue.details.items,
(
movie,
qualityProfile,
showSearchAction,
executingCommands
executingCommands,
queueItems
) => {
// If a movie is deleted this selector may fire before the parent
@ -62,12 +64,25 @@ function createMapStateToProps() {
);
});
let queueStatus = null;
let queueState = null;
for (const q in queueItems) {
if (queueItems[q].movieId === movie.id) {
queueStatus = queueItems[q].status;
queueState = queueItems[q].trackedDownloadState;
break;
}
}
return {
...movie,
qualityProfile,
showSearchAction,
isRefreshingMovie,
isSearchingMovie
isSearchingMovie,
queueStatus,
queueState
};
}
);

@ -97,3 +97,8 @@ $hoverScale: 1.05;
.externalLinks {
margin-right: 0.5em;
}
.queue {
padding-left: 2px;
border-left: 4px solid $queueColor;
}

@ -113,6 +113,8 @@ class MovieIndexOverview extends Component {
isMovieEditorActive,
isSelected,
onSelectedChange,
queueStatus,
queueState,
...otherProps
} = this.props;
@ -170,6 +172,8 @@ class MovieIndexOverview extends Component {
status={status}
posterWidth={posterWidth}
detailedProgressBar={overviewOptions.detailedProgressBar}
queueStatus={queueStatus}
queueState={queueState}
/>
</div>
@ -300,7 +304,9 @@ MovieIndexOverview.propTypes = {
onSelectedChange: PropTypes.func.isRequired,
tmdbId: PropTypes.number.isRequired,
imdbId: PropTypes.string,
youTubeTrailerId: PropTypes.string
youTubeTrailerId: PropTypes.string,
queueStatus: PropTypes.string,
queueState: PropTypes.string
};
export default MovieIndexOverview;

@ -108,6 +108,8 @@ class MovieIndexPoster extends Component {
isMovieEditorActive,
isSelected,
onSelectedChange,
queueStatus,
queueState,
...otherProps
} = this.props;
@ -224,6 +226,8 @@ class MovieIndexPoster extends Component {
status={status}
posterWidth={posterWidth}
detailedProgressBar={detailedProgressBar}
queueStatus={queueStatus}
queueState={queueState}
/>
{
@ -301,7 +305,9 @@ MovieIndexPoster.propTypes = {
onSelectedChange: PropTypes.func.isRequired,
tmdbId: PropTypes.number.isRequired,
imdbId: PropTypes.string,
youTubeTrailerId: PropTypes.string
youTubeTrailerId: PropTypes.string,
queueStatus: PropTypes.string,
queueState: PropTypes.string
};
MovieIndexPoster.defaultProps = {

@ -3,6 +3,9 @@ import React from 'react';
import ProgressBar from 'Components/ProgressBar';
import { sizes } from 'Helpers/Props';
import getProgressBarKind from 'Utilities/Movie/getProgressBarKind';
import getQueueStatusText from 'Utilities/Movie/getQueueStatusText';
import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate';
import styles from './MovieIndexProgressBar.css';
function MovieIndexProgressBar(props) {
@ -11,20 +14,43 @@ function MovieIndexProgressBar(props) {
status,
hasFile,
posterWidth,
detailedProgressBar
detailedProgressBar,
queueStatus,
queueState
} = props;
const progress = 100;
const queueStatusText = getQueueStatusText(queueStatus, queueState);
let movieStatus = (status === 'released' && hasFile) ? 'downloaded' : status;
if (movieStatus === 'deleted') {
movieStatus = 'announced';
if (hasFile) {
movieStatus = 'downloaded';
} else {
movieStatus = 'released';
}
}
if (movieStatus === 'announced') {
movieStatus = translate('NotAvailable');
}
if (movieStatus === 'released') {
movieStatus = translate('Missing');
}
return (
<ProgressBar
className={styles.progressBar}
containerClassName={styles.progress}
progress={progress}
kind={getProgressBarKind(status, monitored, hasFile)}
kind={getProgressBarKind(status, monitored, hasFile, queueStatusText)}
size={detailedProgressBar ? sizes.MEDIUM : sizes.SMALL}
showText={false} // Hide until we have multi version support
showText={detailedProgressBar}
width={posterWidth}
text={(queueStatusText) ? queueStatusText.shortText : titleCase(movieStatus)}
/>
);
}
@ -34,7 +60,9 @@ MovieIndexProgressBar.propTypes = {
hasFile: PropTypes.bool.isRequired,
status: PropTypes.string.isRequired,
posterWidth: PropTypes.number.isRequired,
detailedProgressBar: PropTypes.bool.isRequired
detailedProgressBar: PropTypes.bool.isRequired,
queueStatus: PropTypes.string,
queueState: PropTypes.string
};
export default MovieIndexProgressBar;

@ -98,6 +98,8 @@ class MovieIndexRow extends Component {
onRefreshMoviePress,
onSearchPress,
onSelectedChange,
queueStatus,
queueState,
movieRuntimeFormat
} = this.props;
@ -315,6 +317,8 @@ class MovieIndexRow extends Component {
>
<MovieFileStatusConnector
movieId={id}
queueStatus={queueStatus}
queueState={queueState}
/>
</VirtualTableRowCell>
);
@ -464,6 +468,8 @@ MovieIndexRow.propTypes = {
tmdbId: PropTypes.number.isRequired,
imdbId: PropTypes.string,
youTubeTrailerId: PropTypes.string,
queueStatus: PropTypes.string,
queueState: PropTypes.string,
movieRuntimeFormat: PropTypes.string.isRequired
};

@ -1,11 +1,9 @@
import PropTypes from 'prop-types';
import React from 'react';
import QueueDetails from 'Activity/Queue/QueueDetails';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import ProgressBar from 'Components/ProgressBar';
import { icons, kinds, sizes } from 'Helpers/Props';
import { kinds } from 'Helpers/Props';
import MovieQuality from 'Movie/MovieQuality';
import getQueueStatusText from 'Utilities/Movie/getQueueStatusText';
import translate from 'Utilities/String/translate';
import styles from './MovieFileStatus.css';
@ -13,47 +11,25 @@ function MovieFileStatus(props) {
const {
isAvailable,
monitored,
grabbed,
queueItem,
movieFile
movieFile,
queueStatus,
queueState
} = props;
const hasMovieFile = !!movieFile;
const isQueued = !!queueItem;
const hasReleased = isAvailable;
if (isQueued) {
const {
sizeleft,
size
} = queueItem;
if (queueStatus) {
const queueStatusText = getQueueStatusText(queueStatus, queueState);
const progress = (100 - sizeleft / size * 100);
return (
<div className={styles.center}>
<QueueDetails
{...queueItem}
progressBar={
<ProgressBar
title={translate('MovieIsDownloadingInterp', [progress.toFixed(1), queueItem.title])}
progress={progress}
kind={kinds.PURPLE}
size={sizes.MEDIUM}
/>
}
/>
</div>
);
}
if (grabbed) {
return (
<div className={styles.center}>
<Icon
name={icons.DOWNLOADING}
title={translate('MovieIsDownloading')}
/>
<Label
title={queueStatusText.longText}
kind={kinds.QUEUE}
>
{queueStatusText.shortText}
</Label>
</div>
);
}
@ -115,9 +91,9 @@ function MovieFileStatus(props) {
MovieFileStatus.propTypes = {
isAvailable: PropTypes.bool,
monitored: PropTypes.bool.isRequired,
grabbed: PropTypes.bool,
queueItem: PropTypes.object,
movieFile: PropTypes.object
movieFile: PropTypes.object,
queueStatus: PropTypes.string,
queueState: PropTypes.string
};
export default MovieFileStatus;

@ -4,14 +4,12 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createMovieSelector from 'Store/Selectors/createMovieSelector';
import createQueueItemSelector from 'Store/Selectors/createQueueItemSelector';
import MovieFileStatus from './MovieFileStatus';
function createMapStateToProps() {
return createSelector(
createMovieSelector(),
createQueueItemSelector(),
(movie, queueItem) => {
(movie) => {
const result = _.pick(movie, [
'inCinemas',
'isAvailable',
@ -19,7 +17,6 @@ function createMapStateToProps() {
'grabbed'
]);
result.queueItem = queueItem;
result.movieFile = movie.movieFile;
return result;
@ -45,7 +42,9 @@ class MovieFileStatusConnector extends Component {
}
MovieFileStatusConnector.propTypes = {
movieId: PropTypes.number.isRequired
movieId: PropTypes.number.isRequired,
queueStatus: PropTypes.string,
queueState: PropTypes.string
};
export default connect(createMapStateToProps, mapDispatchToProps)(MovieFileStatusConnector);

@ -231,12 +231,7 @@ export const actionHandlers = handleThunks({
params = getState().queue.details.params;
}
// Ensure there are params before trying to fetch the queue
// so we don't make a bad request to the server.
if (params && !_.isEmpty(params)) {
fetchQueueDetailsHelper(getState, params, dispatch);
}
fetchQueueDetailsHelper(getState, params, dispatch);
},
...createServerSideCollectionHandlers(

@ -14,6 +14,7 @@ module.exports = {
dangerColor: '#f05050',
warningColor: '#ffa500',
infoColor: '#5d9cec',
queueColor: '#7a43b6',
purple: '#7a43b6',
pink: '#ff69b4',
radarrYellow,

@ -1,6 +1,10 @@
import { kinds } from 'Helpers/Props';
function getProgressBarKind(status, monitored, hasFile) {
function getProgressBarKind(status, monitored, hasFile, queue = false) {
if (queue) {
return kinds.QUEUE;
}
if (status === 'announced') {
return kinds.PRIMARY;
}

@ -0,0 +1,61 @@
import titleCase from 'Utilities/String/titleCase';
import translate from 'Utilities/String/translate';
export default function getQueueStatusText(queueStatus, queueState) {
if (!queueStatus) {
return;
}
let statusLong = translate('Downloading');
let statusShort = translate('Downloading');
switch (true) {
case queueStatus !== 'completed':
switch (queueStatus) {
case 'queue':
case 'paused':
case 'failed':
statusLong = `${translate('Downloading')}: ${translate(titleCase(queueStatus))}`;
statusShort = titleCase(queueStatus);
break;
case 'delay':
statusLong = `${translate('Downloading')}: ${translate('Pending')}`;
statusShort = translate('Pending');
break;
case 'DownloadClientUnavailable':
case 'warning':
statusLong = `${translate('Downloading')}: ${translate('Error')}`;
statusShort = translate('Error');
break;
case 'downloading':
statusLong = titleCase(queueStatus);
statusShort = titleCase(queueStatus);
break;
default:
}
break;
case queueStatus === 'completed':
switch (queueState) {
case 'importPending':
statusLong = `${translate('Downloaded')}: ${translate('Pending')}`;
statusShort = translate('Downloaded');
break;
case 'importing':
statusLong = `${translate('Downloaded')}: ${translate('Importing')}`;
statusShort = translate('Downloaded');
break;
case 'failedPending':
statusLong = `${translate('Downloaded')}: ${translate('Waiting')}`;
statusShort = translate('Downloaded');
break;
default:
}
break;
default:
}
const result = { longText: statusLong, shortText: statusShort };
return result;
}

@ -762,6 +762,7 @@
"UnableToLoadUISettings": "Unable to load UI settings",
"Unavailable": "Unavailable",
"Ungroup": "Ungroup",
"Unreleased": "Unreleased",
"UnmappedFolders": "Unmapped Folders",
"Unmonitored": "Unmonitored",
"UnmonitoredHelpText": "Include unmonitored movies in the iCal feed",

Loading…
Cancel
Save