Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion frontend/src/Book/Details/BookDetails.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import React, { Component, Fragment } from 'react';
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
import AuthorHistoryTable from 'Author/History/AuthorHistoryTable';
import DeleteBookModal from 'Book/Delete/DeleteBookModal';
Expand Down Expand Up @@ -117,7 +117,10 @@ class BookDetails extends Component {
nextBook,
hasBookNavigation,
isSearching,
isRePushing,
showRePush,
onRefreshPress,
onRePushPress,
onSearchPress,
statistics = {}
} = this.props;
Expand Down Expand Up @@ -172,6 +175,23 @@ class BookDetails extends Component {

<PageToolbarSeparator />

{
showRePush ?
<Fragment>
<PageToolbarButton
label={translate('ResendToCalibre')}
title={translate('ResendToCalibreContentServerConnections')}
iconName={icons.EXPORT}
isDisabled={!hasBookFiles}
isSpinning={isRePushing}
onPress={onRePushPress}
/>

<PageToolbarSeparator />
</Fragment> :
null
}

<PageToolbarButton
label={translate('Edit')}
iconName={icons.EDIT}
Expand Down Expand Up @@ -400,6 +420,8 @@ BookDetails.propTypes = {
isSaving: PropTypes.bool.isRequired,
isRefreshing: PropTypes.bool,
isSearching: PropTypes.bool,
isRePushing: PropTypes.bool,
showRePush: PropTypes.bool,
isFetching: PropTypes.bool,
isPopulated: PropTypes.bool,
bookFilesError: PropTypes.object,
Expand All @@ -413,6 +435,7 @@ BookDetails.propTypes = {
isSmallScreen: PropTypes.bool.isRequired,
onMonitorTogglePress: PropTypes.func.isRequired,
onRefreshPress: PropTypes.func,
onRePushPress: PropTypes.func,
onSearchPress: PropTypes.func.isRequired
};

Expand Down
24 changes: 23 additions & 1 deletion frontend/src/Book/Details/BookDetailsConnector.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { executeCommand } from 'Store/Actions/commandActions';
import { clearEditions, fetchEditions } from 'Store/Actions/editionActions';
import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions';
import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions';
import { fetchNotifications } from 'Store/Actions/settingsActions';
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
Expand Down Expand Up @@ -51,7 +52,8 @@ function createMapStateToProps() {
createCommandsSelector(),
createUISettingsSelector(),
createDimensionsSelector(),
(bookId, bookFiles, books, editions, authors, commands, uiSettings, dimensions) => {
(state) => state.settings.notifications.items,
(bookId, bookFiles, books, editions, authors, commands, uiSettings, dimensions, notifications) => {
try {
const book = books.items.find((b) => b.id === bookId);

Expand Down Expand Up @@ -106,6 +108,13 @@ function createMapStateToProps() {
isSearchingCommand.body.bookIds &&
isSearchingCommand.body.bookIds.indexOf(book.id) > -1
);
const rePushCommand = findCommand(commands, { name: commandNames.REPUSH_BOOK });
const isRePushing = !!(
rePushCommand &&
isCommandExecuting(rePushCommand) &&
rePushCommand.body &&
rePushCommand.body.bookId === book.id
);
const isRenamingFiles = isCommandExecuting(findCommand(commands, { name: commandNames.RENAME_FILES, authorId: author.id }));
const isRenamingAuthorCommand = findCommand(commands, { name: commandNames.RENAME_AUTHOR });
const isRenamingAuthor = (
Expand Down Expand Up @@ -140,6 +149,8 @@ function createMapStateToProps() {
author,
isRefreshing,
isSearching,
isRePushing,
showRePush: notifications.some((n) => n.implementation === 'CalibreContentServer'),
isRenamingFiles,
isRenamingAuthor,
isFetching,
Expand All @@ -163,6 +174,7 @@ function createMapStateToProps() {

const mapDispatchToProps = {
executeCommand,
fetchNotifications,
fetchBookFiles,
clearBookFiles,
fetchEditions,
Expand Down Expand Up @@ -228,6 +240,7 @@ class BookDetailsConnector extends Component {
this.props.fetchBookFiles({ bookId });
this.props.fetchEditions({ bookId });
this.props.fetchQueueDetails({ bookIds: [bookId] });
this.props.fetchNotifications();
};

unpopulate = () => {
Expand All @@ -248,6 +261,13 @@ class BookDetailsConnector extends Component {
});
};

onRePushPress = () => {
this.props.executeCommand({
name: commandNames.REPUSH_BOOK,
bookId: this.props.id
});
};

onRefreshPress = () => {
this.props.executeCommand({
name: commandNames.REFRESH_BOOK,
Expand All @@ -271,6 +291,7 @@ class BookDetailsConnector extends Component {
{...this.props}
onMonitorTogglePress={this.onMonitorTogglePress}
onRefreshPress={this.onRefreshPress}
onRePushPress={this.onRePushPress}
onSearchPress={this.onSearchPress}
/>
);
Expand All @@ -295,6 +316,7 @@ BookDetailsConnector.propTypes = {
clearReleases: PropTypes.func.isRequired,
cancelFetchReleases: PropTypes.func.isRequired,
toggleBooksMonitored: PropTypes.func.isRequired,
fetchNotifications: PropTypes.func.isRequired,
executeCommand: PropTypes.func.isRequired
};

Expand Down
49 changes: 47 additions & 2 deletions frontend/src/Book/Editor/BookEditorFooter.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import * as commandNames from 'Commands/commandNames';
import SelectInput from 'Components/Form/SelectInput';
import SpinnerButton from 'Components/Link/SpinnerButton';
import PageContentFooter from 'Components/Page/PageContentFooter';
import { kinds } from 'Helpers/Props';
import { executeCommand } from 'Store/Actions/commandActions';
import { fetchNotifications } from 'Store/Actions/settingsActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import translate from 'Utilities/String/translate';
import BookEditorFooterLabel from './BookEditorFooterLabel';
import DeleteBookModal from './Delete/DeleteBookModal';
Expand All @@ -30,6 +35,10 @@ class BookEditorFooter extends Component {
};
}

componentDidMount() {
this.props.fetchNotifications();
}

componentDidUpdate(prevProps) {
const {
isSaving,
Expand Down Expand Up @@ -64,6 +73,13 @@ class BookEditorFooter extends Component {
}
};

onResendToCalibrePress = () => {
this.props.executeCommand({
name: commandNames.REPUSH_BOOK,
bookIds: this.props.bookIds
});
};

onDeleteSelectedPress = () => {
this.setState({ isDeleteBookModalOpen: true });
};
Expand All @@ -80,7 +96,9 @@ class BookEditorFooter extends Component {
bookIds,
selectedCount,
isSaving,
isDeleting
isDeleting,
isResendingToCalibre,
showResendToCalibre
} = this.props;

const {
Expand Down Expand Up @@ -119,6 +137,20 @@ class BookEditorFooter extends Component {
/>

<div className={styles.buttons}>
{
showResendToCalibre ?
<SpinnerButton
className={styles.organizeSelectedButton}
kind={kinds.WARNING}
isSpinning={isResendingToCalibre}
isDisabled={!selectedCount || isResendingToCalibre}
onPress={this.onResendToCalibrePress}
>
{translate('ResendToCalibre')}
</SpinnerButton> :
null
}

<SpinnerButton
className={styles.deleteSelectedButton}
kind={kinds.DANGER}
Expand All @@ -144,6 +176,10 @@ class BookEditorFooter extends Component {
}

BookEditorFooter.propTypes = {
isResendingToCalibre: PropTypes.bool.isRequired,
showResendToCalibre: PropTypes.bool.isRequired,
executeCommand: PropTypes.func.isRequired,
fetchNotifications: PropTypes.func.isRequired,
bookIds: PropTypes.arrayOf(PropTypes.number).isRequired,
selectedCount: PropTypes.number.isRequired,
isSaving: PropTypes.bool.isRequired,
Expand All @@ -153,4 +189,13 @@ BookEditorFooter.propTypes = {
onSaveSelected: PropTypes.func.isRequired
};

export default BookEditorFooter;
const selectIsResendingToCalibre = createCommandExecutingSelector(commandNames.REPUSH_BOOK);

function mapStateToProps(state) {
return {
isResendingToCalibre: selectIsResendingToCalibre(state),
showResendToCalibre: state.settings.notifications.items.some((n) => n.implementation === 'CalibreContentServer')
};
}

export default connect(mapStateToProps, { executeCommand, fetchNotifications })(BookEditorFooter);
1 change: 1 addition & 0 deletions frontend/src/Commands/commandNames.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const DOWNLOADED_BOOKS_SCAN = 'DownloadedBooksScan';
export const BOOK_SEARCH = 'BookSearch';
export const INTERACTIVE_IMPORT = 'ManualImport';
export const MISSING_BOOK_SEARCH = 'MissingBookSearch';
export const REPUSH_BOOK = 'RePushBook';
export const MOVE_AUTHOR = 'MoveAuthor';
export const REFRESH_AUTHOR = 'RefreshAuthor';
export const BULK_REFRESH_AUTHOR = 'BulkRefreshAuthor';
Expand Down
2 changes: 2 additions & 0 deletions src/NzbDrone.Core/Localization/Core/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1679,6 +1679,8 @@
"RescanAfterRefreshHelpText": "Rescan the author folder after refreshing the author",
"RescanAfterRefreshHelpTextWarning": "Chaptarr will not automatically detect changes to files when not set to 'Always",
"RescanAuthorFolderAfterRefresh": "Rescan author folder after Refresh",
"ResendToCalibre": "Resend to Calibre",
"ResendToCalibreContentServerConnections": "Resend to Calibre Content Server Connections",
"Reset": "Reset",
"ResetAPIKey": "Reset API Key",
"ResetAPIKeyMessageText": "Are you sure you want to reset your API Key?",
Expand Down
Loading