1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-09-11 12:02:35 +02:00

Fixed: Import movie spinning forever when error is returned

Fixes #4993

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
This commit is contained in:
Qstick 2020-09-11 22:44:45 -04:00
parent 4be83a3367
commit 69071768de
4 changed files with 104 additions and 17 deletions

View File

@ -31,3 +31,7 @@
margin: 0 10px 0 12px;
text-align: left;
}
.importError {
margin-left: 10px;
}

View File

@ -3,11 +3,13 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
// import CheckInput from 'Components/Form/CheckInput';
import FormInputGroup from 'Components/Form/FormInputGroup';
import Icon from 'Components/Icon';
import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContentFooter from 'Components/Page/PageContentFooter';
import { inputTypes, kinds } from 'Helpers/Props';
import Popover from 'Components/Tooltip/Popover';
import { icons, inputTypes, kinds, tooltipPositions } from 'Helpers/Props';
import styles from './ImportMovieFooter.css';
const MIXED = 'mixed';
@ -93,7 +95,10 @@ class ImportMovieFooter extends Component {
isMonitorMixed,
isQualityProfileIdMixed,
isMinimumAvailabilityMixed,
hasUnsearchedItems,
importError,
onImportPress,
onLookupPress,
onCancelLookupPress
} = this.props;
@ -167,27 +172,71 @@ class ImportMovieFooter extends Component {
</SpinnerButton>
{
isLookingUpMovie &&
isLookingUpMovie ?
<Button
className={styles.loadingButton}
kind={kinds.WARNING}
onPress={onCancelLookupPress}
>
Cancel Processing
</Button>
</Button> :
null
}
{
isLookingUpMovie &&
hasUnsearchedItems ?
<Button
className={styles.loadingButton}
kind={kinds.SUCCESS}
onPress={onLookupPress}
>
Start Processing
</Button> :
null
}
{
isLookingUpMovie ?
<LoadingIndicator
className={styles.loading}
size={24}
/>
/> :
null
}
{
isLookingUpMovie &&
'Processing Folders'
isLookingUpMovie ?
'Processing Folders' :
null
}
{
importError ?
<Popover
anchor={
<Icon
className={styles.importError}
name={icons.WARNING}
kind={kinds.WARNING}
/>
}
title="Import Errors"
body={
<ul>
{
importError.responseJSON.map((error, index) => {
return (
<li key={index}>
{error.errorMessage}
</li>
);
})
}
</ul>
}
position={tooltipPositions.RIGHT}
/> :
null
}
</div>
</div>
@ -206,8 +255,11 @@ ImportMovieFooter.propTypes = {
isMonitorMixed: PropTypes.bool.isRequired,
isQualityProfileIdMixed: PropTypes.bool.isRequired,
isMinimumAvailabilityMixed: PropTypes.bool.isRequired,
hasUnsearchedItems: PropTypes.bool.isRequired,
importError: PropTypes.object,
onInputChange: PropTypes.func.isRequired,
onImportPress: PropTypes.func.isRequired,
onLookupPress: PropTypes.func.isRequired,
onCancelLookupPress: PropTypes.func.isRequired
};

View File

@ -1,7 +1,7 @@
import _ from 'lodash';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { cancelLookupMovie } from 'Store/Actions/importMovieActions';
import { cancelLookupMovie, lookupUnsearchedMovies } from 'Store/Actions/importMovieActions';
import ImportMovieFooter from './ImportMovieFooter';
function isMixed(items, selectedIds, defaultValue, key) {
@ -25,12 +25,14 @@ function createMapStateToProps() {
const {
isLookingUpMovie,
isImporting,
items
items,
importError
} = importMovie;
const isMonitorMixed = isMixed(items, selectedIds, defaultMonitor, 'monitor');
const isQualityProfileIdMixed = isMixed(items, selectedIds, defaultQualityProfileId, 'qualityProfileId');
const isMinimumAvailabilityMixed = isMixed(items, selectedIds, defaultMinimumAvailability, 'minimumAvailability');
const hasUnsearchedItems = !isLookingUpMovie && items.some((item) => !item.isPopulated);
return {
selectedCount: selectedIds.length,
@ -41,13 +43,16 @@ function createMapStateToProps() {
defaultMinimumAvailability,
isMonitorMixed,
isQualityProfileIdMixed,
isMinimumAvailabilityMixed
isMinimumAvailabilityMixed,
importError,
hasUnsearchedItems
};
}
);
}
const mapDispatchToProps = {
onLookupPress: lookupUnsearchedMovies,
onCancelLookupPress: cancelLookupMovie
};

View File

@ -35,6 +35,7 @@ export const defaultState = {
export const QUEUE_LOOKUP_MOVIE = 'importMovie/queueLookupMovie';
export const START_LOOKUP_MOVIE = 'importMovie/startLookupMovie';
export const CANCEL_LOOKUP_MOVIE = 'importMovie/cancelLookupMovie';
export const LOOKUP_UNSEARCHED_MOVIES = 'importMovie/lookupUnsearchedMovies';
export const CLEAR_IMPORT_MOVIE = 'importMovie/clearImportMovie';
export const SET_IMPORT_MOVIE_VALUE = 'importMovie/setImportMovieValue';
export const IMPORT_MOVIE = 'importMovie/importMovie';
@ -45,6 +46,7 @@ export const IMPORT_MOVIE = 'importMovie/importMovie';
export const queueLookupMovie = createThunk(QUEUE_LOOKUP_MOVIE);
export const startLookupMovie = createThunk(START_LOOKUP_MOVIE);
export const importMovie = createThunk(IMPORT_MOVIE);
export const lookupUnsearchedMovies = createThunk(LOOKUP_UNSEARCHED_MOVIES);
export const clearImportMovie = createAction(CLEAR_IMPORT_MOVIE);
export const cancelLookupMovie = createAction(CANCEL_LOOKUP_MOVIE);
@ -179,6 +181,29 @@ export const actionHandlers = handleThunks({
});
},
[LOOKUP_UNSEARCHED_MOVIES]: function(getState, payload, dispatch) {
const state = getState().importMovie;
if (state.isLookingUpMovie) {
return;
}
state.items.forEach((item) => {
const id = item.id;
if (
!item.isPopulated &&
!queue.includes(id)
) {
queue.push(item.id);
}
});
if (queue.length) {
dispatch(startLookupMovie({ start: true }));
}
},
[IMPORT_MOVIE]: function(getState, payload, dispatch) {
dispatch(set({ section, isImporting: true }));
@ -215,7 +240,8 @@ export const actionHandlers = handleThunks({
set({
section,
isImporting: false,
isImported: true
isImported: true,
importError: null
}),
...data.map((movie) => updateItem({ section: 'movies', ...movie })),
@ -227,19 +253,19 @@ export const actionHandlers = handleThunks({
});
promise.fail((xhr) => {
dispatch(batchActions(
dispatch(batchActions([
set({
section,
isImporting: false,
isImported: true
isImported: true,
importError: xhr
}),
addedIds.map((id) => updateItem({
...addedIds.map((id) => updateItem({
section,
id,
importError: xhr
id
}))
));
]));
});
}
});