Fixed: Better book status column in author details

pull/1237/head
ta264 3 years ago
parent ffc97d8489
commit 12c67891fb

@ -2,28 +2,14 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import BookSearchCellConnector from 'Book/BookSearchCellConnector'; import BookSearchCellConnector from 'Book/BookSearchCellConnector';
import BookTitleLink from 'Book/BookTitleLink'; import BookTitleLink from 'Book/BookTitleLink';
import Label from 'Components/Label';
import MonitorToggleButton from 'Components/MonitorToggleButton'; import MonitorToggleButton from 'Components/MonitorToggleButton';
import StarRating from 'Components/StarRating'; import StarRating from 'Components/StarRating';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector'; import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow'; import TableRow from 'Components/Table/TableRow';
import { kinds, sizes } from 'Helpers/Props'; import BookStatus from './BookStatus';
import translate from 'Utilities/String/translate';
import styles from './BookRow.css'; import styles from './BookRow.css';
function getBookCountKind(monitored, bookFileCount, bookCount) {
if (bookFileCount === bookCount && bookCount > 0) {
return kinds.SUCCESS;
}
if (!monitored) {
return kinds.WARNING;
}
return kinds.DANGER;
}
class BookRow extends Component { class BookRow extends Component {
// //
@ -69,7 +55,6 @@ class BookRow extends Component {
id, id,
authorId, authorId,
monitored, monitored,
statistics,
releaseDate, releaseDate,
title, title,
seriesTitle, seriesTitle,
@ -79,14 +64,12 @@ class BookRow extends Component {
isSaving, isSaving,
authorMonitored, authorMonitored,
titleSlug, titleSlug,
bookFiles,
columns columns
} = this.props; } = this.props;
const { const bookFile = bookFiles[0];
bookCount, const isAvailable = Date.parse(releaseDate) < new Date();
bookFileCount,
totalBookCount
} = statistics;
return ( return (
<TableRow> <TableRow>
@ -196,15 +179,11 @@ class BookRow extends Component {
key={name} key={name}
className={styles.status} className={styles.status}
> >
<Label <BookStatus
title={translate('TotalBookCountBooksTotalBookFileCountBooksWithFilesInterp', [totalBookCount, bookFileCount])} isAvailable={isAvailable}
kind={getBookCountKind(monitored, bookFileCount, bookCount)} monitored={monitored}
size={sizes.MEDIUM} bookFile={bookFile}
> />
{
<span>{bookFileCount} / {bookCount}</span>
}
</Label>
</TableRowCell> </TableRowCell>
); );
} }
@ -240,16 +219,9 @@ BookRow.propTypes = {
titleSlug: PropTypes.string.isRequired, titleSlug: PropTypes.string.isRequired,
isSaving: PropTypes.bool, isSaving: PropTypes.bool,
authorMonitored: PropTypes.bool.isRequired, authorMonitored: PropTypes.bool.isRequired,
statistics: PropTypes.object.isRequired, bookFiles: PropTypes.arrayOf(PropTypes.object).isRequired,
columns: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onMonitorBookPress: PropTypes.func.isRequired onMonitorBookPress: PropTypes.func.isRequired
}; };
BookRow.defaultProps = {
statistics: {
bookCount: 0,
bookFileCount: 0
}
};
export default BookRow; export default BookRow;

@ -2,17 +2,38 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import createAuthorSelector from 'Store/Selectors/createAuthorSelector'; import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
import createBookFileSelector from 'Store/Selectors/createBookFileSelector';
import BookRow from './BookRow'; import BookRow from './BookRow';
const selectBookFiles = createSelector(
(state) => state.bookFiles,
(bookFiles) => {
const {
items
} = bookFiles;
const bookFileDict = items.reduce((acc, file) => {
const bookId = file.bookId;
if (!acc.hasOwnProperty(bookId)) {
acc[bookId] = [];
}
acc[bookId].push(file);
return acc;
}, {});
return bookFileDict;
}
);
function createMapStateToProps() { function createMapStateToProps() {
return createSelector( return createSelector(
createAuthorSelector(), createAuthorSelector(),
createBookFileSelector(), selectBookFiles,
(author = {}, bookFile) => { (state, { id }) => id,
(author = {}, bookFiles, bookId) => {
return { return {
authorMonitored: author.monitored, authorMonitored: author.monitored,
bookFilePath: bookFile ? bookFile.path : null bookFiles: bookFiles[bookId] ?? []
}; };
} }
); );

@ -0,0 +1,5 @@
.center {
display: flex;
justify-content: center;
}

@ -0,0 +1,78 @@
import PropTypes from 'prop-types';
import React from 'react';
import BookQuality from 'Book/BookQuality';
import Label from 'Components/Label';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './BookStatus.css';
function BookStatus(props) {
const {
isAvailable,
monitored,
bookFile
} = props;
const hasBookFile = !!bookFile;
if (hasBookFile) {
const quality = bookFile.quality;
return (
<div className={styles.center}>
<BookQuality
title={quality.quality.name}
size={bookFile.size}
quality={quality}
isMonitored={monitored}
isCutoffNotMet={bookFile.qualityCutoffNotMet}
/>
</div>
);
}
if (!monitored) {
return (
<div className={styles.center}>
<Label
title={translate('NotMonitored')}
kind={kinds.WARNING}
>
{translate('NotMonitored')}
</Label>
</div>
);
}
if (isAvailable) {
return (
<div className={styles.center}>
<Label
title={translate('BookAvailableButMissing')}
kind={kinds.DANGER}
>
{translate('Missing')}
</Label>
</div>
);
}
return (
<div className={styles.center}>
<Label
title={translate('NotAvailable')}
kind={kinds.INFO}
>
{translate('NotAvailable')}
</Label>
</div>
);
}
BookStatus.propTypes = {
isAvailable: PropTypes.bool,
monitored: PropTypes.bool.isRequired,
bookFile: PropTypes.object
};
export default BookStatus;

@ -4,11 +4,7 @@ import Label from 'Components/Label';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
function getTooltip(title, quality, size) { function getTooltip(title, quality, size, isMonitored, isCutoffNotMet) {
if (!title) {
return;
}
const revision = quality.revision; const revision = quality.revision;
if (revision.real && revision.real > 0) { if (revision.real && revision.real > 0) {
@ -23,6 +19,12 @@ function getTooltip(title, quality, size) {
title += ` - ${formatBytes(size)}`; title += ` - ${formatBytes(size)}`;
} }
if (!isMonitored) {
title += ' [Not Monitored]';
} else if (isCutoffNotMet) {
title += ' [Cutoff Not Met]';
}
return title; return title;
} }
@ -32,14 +34,26 @@ function BookQuality(props) {
title, title,
quality, quality,
size, size,
isMonitored,
isCutoffNotMet isCutoffNotMet
} = props; } = props;
let kind = kinds.DEFAULT;
if (!isMonitored) {
kind = kinds.DISABLED;
} else if (isCutoffNotMet) {
kind = kinds.INVERSE;
}
if (!quality) {
return null;
}
return ( return (
<Label <Label
className={className} className={className}
kind={isCutoffNotMet ? kinds.INVERSE : kinds.DEFAULT} kind={kind}
title={getTooltip(title, quality, size)} title={getTooltip(title, quality, size, isMonitored, isCutoffNotMet)}
> >
{quality.quality.name} {quality.quality.name}
</Label> </Label>
@ -51,11 +65,13 @@ BookQuality.propTypes = {
title: PropTypes.string, title: PropTypes.string,
quality: PropTypes.object.isRequired, quality: PropTypes.object.isRequired,
size: PropTypes.number, size: PropTypes.number,
isMonitored: PropTypes.bool,
isCutoffNotMet: PropTypes.bool isCutoffNotMet: PropTypes.bool
}; };
BookQuality.defaultProps = { BookQuality.defaultProps = {
title: '' title: '',
isMonitored: true
}; };
export default BookQuality; export default BookQuality;

@ -105,20 +105,6 @@ export const filterPredicates = {
}; };
export const sortPredicates = { export const sortPredicates = {
status: function(item) {
let result = 0;
if (item.monitored) {
result += 2;
}
if (item.status === 'continuing') {
result++;
}
return result;
},
sizeOnDisk: function(item) { sizeOnDisk: function(item) {
const { statistics = {} } = item; const { statistics = {} } = item;

@ -64,6 +64,7 @@
"BlacklistHelpText": "Prevents Readarr from automatically grabbing these files again", "BlacklistHelpText": "Prevents Readarr from automatically grabbing these files again",
"BlacklistRelease": "Blacklist Release", "BlacklistRelease": "Blacklist Release",
"Book": "Book", "Book": "Book",
"BookAvailableButMissing": "Book Available, but Missing",
"BookDownloaded": "Book Downloaded", "BookDownloaded": "Book Downloaded",
"BookFileCountBookCountTotalTotalBookCountInterp": "{0} / {1} (Total: {2})", "BookFileCountBookCountTotalTotalBookCountInterp": "{0} / {1} (Total: {2})",
"BookFileCounttotalBookCountBooksDownloadedInterp": "{0}/{1} books downloaded", "BookFileCounttotalBookCountBooksDownloadedInterp": "{0}/{1} books downloaded",
@ -402,6 +403,8 @@
"NoMinimumForAnyRuntime": "No minimum for any runtime", "NoMinimumForAnyRuntime": "No minimum for any runtime",
"NoName": "Do not show name", "NoName": "Do not show name",
"None": "None", "None": "None",
"NotAvailable": "Not Available",
"NotMonitored": "Not Monitored",
"NoTagsHaveBeenAddedYet": "No tags have been added yet. Add tags to link authors with delay profiles, restrictions, or notifications. Click {0} to find out more about tags in Readarr.", "NoTagsHaveBeenAddedYet": "No tags have been added yet. Add tags to link authors with delay profiles, restrictions, or notifications. Click {0} to find out more about tags in Readarr.",
"NotificationTriggers": "Notification Triggers", "NotificationTriggers": "Notification Triggers",
"NoUpdatesAreAvailable": "No updates are available", "NoUpdatesAreAvailable": "No updates are available",

Loading…
Cancel
Save