diff --git a/frontend/src/InteractiveImport/Edition/SelectEditionModalContent.js b/frontend/src/InteractiveImport/Edition/SelectEditionModalContent.js
index dc9954fea..e85a30b61 100644
--- a/frontend/src/InteractiveImport/Edition/SelectEditionModalContent.js
+++ b/frontend/src/InteractiveImport/Edition/SelectEditionModalContent.js
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Button from 'Components/Link/Button';
+import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
@@ -9,7 +10,8 @@ import ModalHeader from 'Components/Modal/ModalHeader';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { scrollDirections } from 'Helpers/Props';
-import SelectEditionRow from './SelectEditionRow';
+import translate from 'Utilities/String/translate';
+import SelectEditionRowConnector from './SelectEditionRowConnector';
import styles from './SelectEditionModalContent.css';
const columns = [
@@ -33,15 +35,30 @@ class SelectEditionModalContent extends Component {
render() {
const {
books,
+ isPopulated,
+ isFetching,
+ error,
onEditionSelect,
onModalClose,
...otherProps
} = this.props;
+ if (!isPopulated && !error) {
+ return ();
+ }
+
+ if (!isFetching && error) {
+ return (
+
+ {translate('LoadingEditionsFailed')}
+
+ );
+ }
+
return (
- Manual Import - Select Edition
+ {translate('ManualImportSelectEdition')}
{
return (
-
@@ -86,6 +103,9 @@ class SelectEditionModalContent extends Component {
SelectEditionModalContent.propTypes = {
books: PropTypes.arrayOf(PropTypes.object).isRequired,
+ isFetching: PropTypes.bool,
+ isPopulated: PropTypes.bool,
+ error: PropTypes.object,
onEditionSelect: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
diff --git a/frontend/src/InteractiveImport/Edition/SelectEditionModalContentConnector.js b/frontend/src/InteractiveImport/Edition/SelectEditionModalContentConnector.js
index 564896141..7fb344c5c 100644
--- a/frontend/src/InteractiveImport/Edition/SelectEditionModalContentConnector.js
+++ b/frontend/src/InteractiveImport/Edition/SelectEditionModalContentConnector.js
@@ -1,27 +1,71 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
+import { createSelector } from 'reselect';
+import { clearEditions, fetchEditions } from 'Store/Actions/editionActions';
import {
saveInteractiveImportItem,
updateInteractiveImportItem } from 'Store/Actions/interactiveImportActions';
+import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
import SelectEditionModalContent from './SelectEditionModalContent';
function createMapStateToProps() {
- return {};
+ return createSelector(
+ (state) => state.editions,
+ (editions) => {
+ const {
+ isFetching,
+ isPopulated,
+ error
+ } = editions;
+
+ return {
+ isFetching,
+ isPopulated,
+ error
+ };
+ }
+ );
}
const mapDispatchToProps = {
+ fetchEditions,
+ clearEditions,
updateInteractiveImportItem,
saveInteractiveImportItem
};
class SelectEditionModalContentConnector extends Component {
+ //
+ // Lifecycle
+
+ componentDidMount() {
+ registerPagePopulator(this.populate);
+ this.populate();
+ }
+
+ componentWillUnmount() {
+ unregisterPagePopulator(this.populate);
+ this.unpopulate();
+ }
+ //
+ // Control
+
+ populate = () => {
+ const bookId = this.props.books.map((b) => b.book.id);
+
+ this.props.fetchEditions({ bookId });
+ }
+
+ unpopulate = () => {
+ this.props.clearEditions();
+ }
+
//
// Listeners
onEditionSelect = (bookId, foreignEditionId) => {
- console.log(`book: ${bookId} id: ${foreignEditionId} ${typeof foreignEditionId}`);
const ids = this.props.importIdsByBook[bookId];
ids.forEach((id) => {
@@ -55,6 +99,8 @@ class SelectEditionModalContentConnector extends Component {
SelectEditionModalContentConnector.propTypes = {
importIdsByBook: PropTypes.object.isRequired,
books: PropTypes.arrayOf(PropTypes.object).isRequired,
+ fetchEditions: PropTypes.func.isRequired,
+ clearEditions: PropTypes.func.isRequired,
updateInteractiveImportItem: PropTypes.func.isRequired,
saveInteractiveImportItem: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
diff --git a/frontend/src/InteractiveImport/Edition/SelectEditionRowConnector.js b/frontend/src/InteractiveImport/Edition/SelectEditionRowConnector.js
new file mode 100644
index 000000000..4cdcda585
--- /dev/null
+++ b/frontend/src/InteractiveImport/Edition/SelectEditionRowConnector.js
@@ -0,0 +1,32 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { createSelector } from 'reselect';
+import SelectEditionRow from './SelectEditionRow';
+
+function createMapStateToProps() {
+ return createSelector(
+ (state, { id }) => id,
+ (state) => state.editions,
+ (id, editionState) => {
+ const editions = editionState.items.filter((e) => e.bookId === id);
+ return { editions };
+ }
+ );
+}
+
+class SelectEditionRowConnector extends Component {
+ render() {
+ return (
+
+ );
+ }
+}
+
+SelectEditionRowConnector.PropTypes = {
+ editions: PropTypes.arrayOf(PropTypes.object).isRequired
+};
+
+export default connect(createMapStateToProps)(SelectEditionRowConnector);
diff --git a/src/NzbDrone.Core/Books/Repositories/EditionRepository.cs b/src/NzbDrone.Core/Books/Repositories/EditionRepository.cs
index 04e408ae6..bdd511d28 100644
--- a/src/NzbDrone.Core/Books/Repositories/EditionRepository.cs
+++ b/src/NzbDrone.Core/Books/Repositories/EditionRepository.cs
@@ -11,7 +11,7 @@ namespace NzbDrone.Core.Books
{
List GetAllMonitoredEditions();
Edition FindByForeignEditionId(string foreignEditionId);
- List FindByBook(int id);
+ List FindByBook(IEnumerable ids);
List FindByAuthor(int id);
List FindByAuthorMetadataId(int id, bool onlyMonitored);
Edition FindByTitle(int authorMetadataId, string title);
@@ -43,14 +43,14 @@ namespace NzbDrone.Core.Books
return Query(r => r.BookId == bookId || foreignEditionIds.Contains(r.ForeignEditionId));
}
- public List FindByBook(int id)
+ public List FindByBook(IEnumerable ids)
{
// populate the books and author metadata also
// this hopefully speeds up the track matching a lot
var builder = new SqlBuilder(_database.DatabaseType)
.LeftJoin((e, b) => e.BookId == b.Id)
.LeftJoin((b, a) => b.AuthorMetadataId == a.Id)
- .Where(r => r.BookId == id);
+ .Where(r => ids.Contains(r.BookId));
return _database.QueryJoined(builder, (edition, book, metadata) =>
{
@@ -96,7 +96,7 @@ namespace NzbDrone.Core.Books
public List SetMonitored(Edition edition)
{
- var allEditions = FindByBook(edition.BookId);
+ var allEditions = FindByBook(new[] { edition.BookId });
allEditions.ForEach(r => r.Monitored = r.Id == edition.Id);
Ensure.That(allEditions.Count(x => x.Monitored) == 1).IsTrue();
UpdateMany(allEditions);
diff --git a/src/NzbDrone.Core/Books/Services/EditionService.cs b/src/NzbDrone.Core/Books/Services/EditionService.cs
index a7424fe0e..f2e289556 100644
--- a/src/NzbDrone.Core/Books/Services/EditionService.cs
+++ b/src/NzbDrone.Core/Books/Services/EditionService.cs
@@ -18,6 +18,7 @@ namespace NzbDrone.Core.Books
void DeleteMany(List editions);
List GetEditionsForRefresh(int bookId, List foreignEditionIds);
List GetEditionsByBook(int bookId);
+ List GetEditionsByBook(IEnumerable bookIds);
List GetEditionsByAuthor(int authorId);
Edition FindByTitle(int authorMetadataId, string title);
Edition FindByTitleInexact(int authorMetadataId, string title);
@@ -79,7 +80,12 @@ namespace NzbDrone.Core.Books
public List GetEditionsByBook(int bookId)
{
- return _editionRepository.FindByBook(bookId);
+ return _editionRepository.FindByBook(new[] { bookId });
+ }
+
+ public List GetEditionsByBook(IEnumerable bookIds)
+ {
+ return _editionRepository.FindByBook(bookIds);
}
public List GetEditionsByAuthor(int authorId)
diff --git a/src/NzbDrone.Core/Localization/Core/en.json b/src/NzbDrone.Core/Localization/Core/en.json
index 713dbb20a..3ff678e49 100644
--- a/src/NzbDrone.Core/Localization/Core/en.json
+++ b/src/NzbDrone.Core/Localization/Core/en.json
@@ -381,6 +381,7 @@
"ListsSettingsSummary": "Import Lists",
"LoadingBookFilesFailed": "Loading book files failed",
"LoadingBooksFailed": "Loading books failed",
+ "LoadingEditionsFailed": "Loading editions failed",
"Local": "Local",
"LogFiles": "Log Files",
"Logging": "Logging",
@@ -395,6 +396,7 @@
"MaintenanceRelease": "Maintenance Release: bug fixes and other improvements. See Github Commit History for more details",
"ManualDownload": "Manual Download",
"ManualImport": "Manual Import",
+ "ManualImportSelectEdition": "Manual Import - Select Edition",
"MarkAsFailed": "Mark as Failed",
"MarkAsFailedMessageText": "Are you sure you want to mark '{0}' as failed?",
"MassBookSearch": "Mass Book Search",
diff --git a/src/Readarr.Api.V1/Editions/EditionController.cs b/src/Readarr.Api.V1/Editions/EditionController.cs
index 71aedc399..34d44a957 100644
--- a/src/Readarr.Api.V1/Editions/EditionController.cs
+++ b/src/Readarr.Api.V1/Editions/EditionController.cs
@@ -17,7 +17,7 @@ namespace NzbDrone.Api.V1.Editions
}
[HttpGet]
- public List GetEditions(int bookId)
+ public List GetEditions([FromQuery]List bookId)
{
var editions = _editionService.GetEditionsByBook(bookId);