mirror of
https://github.com/Readarr/Readarr.git
synced 2026-03-05 13:20:32 -05:00
Fixed: Removed unnecessary author data from book endpoint
This commit is contained in:
@@ -8,6 +8,7 @@ import * as commandNames from 'Commands/commandNames';
|
||||
import { toggleBooksMonitored } from 'Store/Actions/bookActions';
|
||||
import { clearBookFiles, fetchBookFiles } from 'Store/Actions/bookFileActions';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import { clearEditions, fetchEditions } from 'Store/Actions/editionActions';
|
||||
import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions';
|
||||
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
|
||||
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
||||
@@ -43,11 +44,12 @@ function createMapStateToProps() {
|
||||
(state, { titleSlug }) => titleSlug,
|
||||
selectBookFiles,
|
||||
(state) => state.books,
|
||||
(state) => state.editions,
|
||||
createAllAuthorSelector(),
|
||||
createCommandsSelector(),
|
||||
createUISettingsSelector(),
|
||||
createDimensionsSelector(),
|
||||
(titleSlug, bookFiles, books, authors, commands, uiSettings, dimensions) => {
|
||||
(titleSlug, bookFiles, books, editions, authors, commands, uiSettings, dimensions) => {
|
||||
const book = books.items.find((b) => b.titleSlug === titleSlug);
|
||||
const author = authors.find((a) => a.id === book.authorId);
|
||||
const sortedBooks = books.items.filter((b) => b.authorId === book.authorId);
|
||||
@@ -79,8 +81,8 @@ function createMapStateToProps() {
|
||||
isRefreshingCommand.body.bookId === book.id
|
||||
);
|
||||
|
||||
const isFetching = isBookFilesFetching;
|
||||
const isPopulated = isBookFilesPopulated;
|
||||
const isFetching = isBookFilesFetching || editions.isFetching;
|
||||
const isPopulated = isBookFilesPopulated && editions.isPopulated;
|
||||
|
||||
return {
|
||||
...book,
|
||||
@@ -104,6 +106,8 @@ const mapDispatchToProps = {
|
||||
executeCommand,
|
||||
fetchBookFiles,
|
||||
clearBookFiles,
|
||||
fetchEditions,
|
||||
clearEditions,
|
||||
clearReleases,
|
||||
cancelFetchReleases,
|
||||
toggleBooksMonitored
|
||||
@@ -121,7 +125,8 @@ class BookDetailsConnector extends Component {
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (!_.isEqual(getMonitoredEditions(prevProps), getMonitoredEditions(this.props)) ||
|
||||
if (prevProps.id !== this.props.id ||
|
||||
!_.isEqual(getMonitoredEditions(prevProps), getMonitoredEditions(this.props)) ||
|
||||
(prevProps.anyReleaseOk === false && this.props.anyReleaseOk === true)) {
|
||||
this.unpopulate();
|
||||
this.populate();
|
||||
@@ -140,12 +145,14 @@ class BookDetailsConnector extends Component {
|
||||
const bookId = this.props.id;
|
||||
|
||||
this.props.fetchBookFiles({ bookId });
|
||||
this.props.fetchEditions({ bookId });
|
||||
}
|
||||
|
||||
unpopulate = () => {
|
||||
this.props.cancelFetchReleases();
|
||||
this.props.clearReleases();
|
||||
this.props.clearBookFiles();
|
||||
this.props.clearEditions();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -195,6 +202,8 @@ BookDetailsConnector.propTypes = {
|
||||
titleSlug: PropTypes.string.isRequired,
|
||||
fetchBookFiles: PropTypes.func.isRequired,
|
||||
clearBookFiles: PropTypes.func.isRequired,
|
||||
fetchEditions: PropTypes.func.isRequired,
|
||||
clearEditions: PropTypes.func.isRequired,
|
||||
clearReleases: PropTypes.func.isRequired,
|
||||
cancelFetchReleases: PropTypes.func.isRequired,
|
||||
toggleBooksMonitored: PropTypes.func.isRequired,
|
||||
|
||||
@@ -8,15 +8,25 @@ import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||
import BookDetailsHeader from './BookDetailsHeader';
|
||||
|
||||
const selectOverview = createSelector(
|
||||
(state) => state.editions,
|
||||
(editions) => {
|
||||
const monitored = editions.items.find((e) => e.monitored === true);
|
||||
return monitored?.overview;
|
||||
}
|
||||
);
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createBookSelector(),
|
||||
selectOverview,
|
||||
createUISettingsSelector(),
|
||||
createDimensionsSelector(),
|
||||
(book, uiSettings, dimensions) => {
|
||||
(book, overview, uiSettings, dimensions) => {
|
||||
|
||||
return {
|
||||
...book,
|
||||
overview,
|
||||
shortDateFormat: uiSettings.shortDateFormat,
|
||||
isSmallScreen: dimensions.isSmallScreen
|
||||
};
|
||||
|
||||
@@ -53,7 +53,7 @@ class EditBookModalContent extends Component {
|
||||
editions
|
||||
} = item;
|
||||
|
||||
const hasFile = statistics ? statistics.bookFileCount : 0;
|
||||
const hasFile = statistics ? statistics.bookFileCount > 0 : false;
|
||||
const errorMessage = getErrorMessage(error, 'Unable to load editions');
|
||||
|
||||
return (
|
||||
|
||||
@@ -4,7 +4,7 @@ import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { saveBook, setBookValue } from 'Store/Actions/bookActions';
|
||||
import { clearEditions, fetchEditions } from 'Store/Actions/editionActions';
|
||||
import { saveEditions } from 'Store/Actions/editionActions';
|
||||
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||
import createBookSelector from 'Store/Selectors/createBookSelector';
|
||||
import selectSettings from 'Store/Selectors/selectSettings';
|
||||
@@ -26,17 +26,14 @@ function createMapStateToProps() {
|
||||
const {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
items
|
||||
error
|
||||
} = editionState;
|
||||
|
||||
book.editions = items;
|
||||
|
||||
const bookSettings = _.pick(book, [
|
||||
'monitored',
|
||||
'anyEditionOk',
|
||||
'editions'
|
||||
'anyEditionOk'
|
||||
]);
|
||||
bookSettings.editions = editionState.items;
|
||||
|
||||
const settings = selectSettings(bookSettings, pendingChanges, saveError);
|
||||
|
||||
@@ -58,10 +55,9 @@ function createMapStateToProps() {
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
dispatchFetchEditions: fetchEditions,
|
||||
dispatchClearEditions: clearEditions,
|
||||
dispatchSetBookValue: setBookValue,
|
||||
dispatchSaveBook: saveBook
|
||||
dispatchSaveBook: saveBook,
|
||||
dispatchSaveEditions: saveEditions
|
||||
};
|
||||
|
||||
class EditBookModalContentConnector extends Component {
|
||||
@@ -69,20 +65,12 @@ class EditBookModalContentConnector extends Component {
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatchFetchEditions({ bookId: this.props.bookId });
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (prevProps.isSaving && !this.props.isSaving && !this.props.saveError) {
|
||||
this.props.onModalClose();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.dispatchClearEditions();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
@@ -94,6 +82,9 @@ class EditBookModalContentConnector extends Component {
|
||||
this.props.dispatchSaveBook({
|
||||
id: this.props.bookId
|
||||
});
|
||||
this.props.dispatchSaveEditions({
|
||||
id: this.props.bookId
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
@@ -114,10 +105,9 @@ EditBookModalContentConnector.propTypes = {
|
||||
bookId: PropTypes.number,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
saveError: PropTypes.object,
|
||||
dispatchFetchEditions: PropTypes.func.isRequired,
|
||||
dispatchClearEditions: PropTypes.func.isRequired,
|
||||
dispatchSetBookValue: PropTypes.func.isRequired,
|
||||
dispatchSaveBook: PropTypes.func.isRequired,
|
||||
dispatchSaveEditions: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import createBookAuthorSelector from 'Store/Selectors/createBookAuthorSelector';
|
||||
import createBookQualityProfileSelector from 'Store/Selectors/createBookQualityProfileSelector';
|
||||
import createBookSelector from 'Store/Selectors/createBookSelector';
|
||||
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
|
||||
@@ -32,11 +33,13 @@ function selectShowSearchAction() {
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createBookSelector(),
|
||||
createBookAuthorSelector(),
|
||||
createBookQualityProfileSelector(),
|
||||
selectShowSearchAction(),
|
||||
createExecutingCommandsSelector(),
|
||||
(
|
||||
book,
|
||||
author,
|
||||
qualityProfile,
|
||||
showSearchAction,
|
||||
executingCommands
|
||||
@@ -54,7 +57,7 @@ function createMapStateToProps() {
|
||||
const isRefreshingBook = executingCommands.some((command) => {
|
||||
return (
|
||||
(command.name === commandNames.REFRESH_AUTHOR &&
|
||||
command.body.authorId === book.author.id) ||
|
||||
command.body.authorId === book.authorId) ||
|
||||
(command.name === commandNames.REFRESH_BOOK &&
|
||||
command.body.bookId === book.id)
|
||||
);
|
||||
@@ -63,7 +66,7 @@ function createMapStateToProps() {
|
||||
const isSearchingBook = executingCommands.some((command) => {
|
||||
return (
|
||||
(command.name === commandNames.AUTHOR_SEARCH &&
|
||||
command.body.authorId === book.author.id) ||
|
||||
command.body.authorId === book.authorId) ||
|
||||
(command.name === commandNames.BOOK_SEARCH &&
|
||||
command.body.bookIds.includes(book.id))
|
||||
);
|
||||
@@ -71,6 +74,7 @@ function createMapStateToProps() {
|
||||
|
||||
return {
|
||||
...book,
|
||||
author,
|
||||
qualityProfile,
|
||||
showSearchAction,
|
||||
isRefreshingBook,
|
||||
|
||||
@@ -12,6 +12,7 @@ import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import dimensions from 'Styles/Variables/dimensions';
|
||||
import fonts from 'Styles/Variables/fonts';
|
||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||
import stripHtml from 'Utilities/String/stripHtml';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import BookIndexOverviewInfo from './BookIndexOverviewInfo';
|
||||
@@ -42,10 +43,26 @@ class BookIndexOverview extends Component {
|
||||
|
||||
this.state = {
|
||||
isEditAuthorModalOpen: false,
|
||||
isDeleteAuthorModalOpen: false
|
||||
isDeleteAuthorModalOpen: false,
|
||||
overview: ''
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { id } = this.props;
|
||||
|
||||
// Note that this component is lazy loaded by the virtualised view.
|
||||
// We want to avoid storing overviews for *all* books which is
|
||||
// why it's not put into the redux store
|
||||
const promise = createAjaxRequest({
|
||||
url: `/book/${id}/overview`
|
||||
}).request;
|
||||
|
||||
promise.done((data) => {
|
||||
this.setState({ overview: data.overview });
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
@@ -84,7 +101,6 @@ class BookIndexOverview extends Component {
|
||||
const {
|
||||
id,
|
||||
title,
|
||||
overview,
|
||||
monitored,
|
||||
titleSlug,
|
||||
nextAiring,
|
||||
@@ -118,6 +134,7 @@ class BookIndexOverview extends Component {
|
||||
} = statistics;
|
||||
|
||||
const {
|
||||
overview,
|
||||
isEditAuthorModalOpen,
|
||||
isDeleteAuthorModalOpen
|
||||
} = this.state;
|
||||
@@ -267,7 +284,6 @@ class BookIndexOverview extends Component {
|
||||
BookIndexOverview.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
overview: PropTypes.string.isRequired,
|
||||
monitored: PropTypes.bool.isRequired,
|
||||
titleSlug: PropTypes.string.isRequired,
|
||||
nextAiring: PropTypes.string,
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { createAction } from 'redux-actions';
|
||||
import { batchActions } from 'redux-batched-actions';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import getProviderState from 'Utilities/State/getProviderState';
|
||||
import { updateItem } from './baseActions';
|
||||
import createFetchHandler from './Creators/createFetchHandler';
|
||||
import createHandleActions from './Creators/createHandleActions';
|
||||
import createClearReducer from './Creators/Reducers/createClearReducer';
|
||||
@@ -25,18 +28,39 @@ export const defaultState = {
|
||||
|
||||
export const FETCH_EDITIONS = 'editions/fetchEditions';
|
||||
export const CLEAR_EDITIONS = 'editions/clearEditions';
|
||||
export const SAVE_EDITIONS = 'editions/saveEditions';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchEditions = createThunk(FETCH_EDITIONS);
|
||||
export const clearEditions = createAction(CLEAR_EDITIONS);
|
||||
export const saveEditions = createThunk(SAVE_EDITIONS);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
[FETCH_EDITIONS]: createFetchHandler(section, '/edition')
|
||||
[FETCH_EDITIONS]: createFetchHandler(section, '/edition'),
|
||||
|
||||
[SAVE_EDITIONS]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
id,
|
||||
...otherPayload
|
||||
} = payload;
|
||||
|
||||
const saveData = getProviderState({ id, ...otherPayload }, getState, 'books');
|
||||
|
||||
dispatch(batchActions([
|
||||
...saveData.editions.map((edition) => {
|
||||
return updateItem({
|
||||
id: edition.id,
|
||||
section: 'editions',
|
||||
...edition
|
||||
});
|
||||
})
|
||||
]));
|
||||
}
|
||||
});
|
||||
|
||||
//
|
||||
|
||||
15
frontend/src/Store/Selectors/createBookAuthorSelector.js
Normal file
15
frontend/src/Store/Selectors/createBookAuthorSelector.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import { createSelector } from 'reselect';
|
||||
import createBookSelector from './createBookSelector';
|
||||
|
||||
function createBookAuthorSelector() {
|
||||
return createSelector(
|
||||
createBookSelector(),
|
||||
(state) => state.authors.itemMap,
|
||||
(state) => state.authors.items,
|
||||
(book, authorMap, allAuthors) => {
|
||||
return allAuthors[authorMap[book.authorId]];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default createBookAuthorSelector;
|
||||
@@ -1,18 +1,16 @@
|
||||
import { createSelector } from 'reselect';
|
||||
import createBookSelector from './createBookSelector';
|
||||
import createBookAuthorSelector from './createBookAuthorSelector';
|
||||
|
||||
function createBookQualityProfileSelector() {
|
||||
return createSelector(
|
||||
(state) => state.settings.qualityProfiles.items,
|
||||
createBookSelector(),
|
||||
(qualityProfiles, book) => {
|
||||
if (!book) {
|
||||
createBookAuthorSelector(),
|
||||
(qualityProfiles, author) => {
|
||||
if (!author) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return qualityProfiles.find((profile) => {
|
||||
return profile.id === book.author.qualityProfileId;
|
||||
});
|
||||
return qualityProfiles.find((profile) => profile.id === author.qualityProfileId);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user