mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-22 22:14:44 -04:00
Renames in Frontend
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import SelectBookModalContentConnector from './SelectBookModalContentConnector';
|
||||
|
||||
class SelectBookModal extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<SelectBookModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectBookModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectBookModal;
|
||||
@@ -0,0 +1,18 @@
|
||||
.modalBody {
|
||||
composes: modalBody from '~Components/Modal/ModalBody.css';
|
||||
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.filterInput {
|
||||
composes: input from '~Components/Form/TextInput.css';
|
||||
|
||||
flex: 0 0 auto;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.scroller {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Button from 'Components/Link/Button';
|
||||
import { scrollDirections } from 'Helpers/Props';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import Scroller from 'Components/Scroller/Scroller';
|
||||
import TextInput from 'Components/Form/TextInput';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import SelectBookRow from './SelectBookRow';
|
||||
import styles from './SelectBookModalContent.css';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'title',
|
||||
label: 'Book Title',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'releaseDate',
|
||||
label: 'Release Date',
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'status',
|
||||
label: 'Book Status',
|
||||
isVisible: true
|
||||
}
|
||||
];
|
||||
|
||||
class SelectBookModalContent extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
filter: ''
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onFilterChange = ({ value }) => {
|
||||
this.setState({ filter: value.toLowerCase() });
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
items,
|
||||
onBookSelect,
|
||||
onModalClose,
|
||||
isFetching,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
const filter = this.state.filter;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Manual Import - Select Book
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody
|
||||
className={styles.modalBody}
|
||||
scrollDirection={scrollDirections.NONE}
|
||||
>
|
||||
{
|
||||
isFetching &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
<TextInput
|
||||
className={styles.filterInput}
|
||||
placeholder="Filter book"
|
||||
name="filter"
|
||||
value={filter}
|
||||
autoFocus={true}
|
||||
onChange={this.onFilterChange}
|
||||
/>
|
||||
|
||||
<Scroller className={styles.scroller}>
|
||||
{
|
||||
<Table
|
||||
columns={columns}
|
||||
{...otherProps}
|
||||
>
|
||||
<TableBody>
|
||||
{
|
||||
items.map((item) => {
|
||||
return item.title.toLowerCase().includes(filter) ?
|
||||
(
|
||||
<SelectBookRow
|
||||
key={item.id}
|
||||
columns={columns}
|
||||
onBookSelect={onBookSelect}
|
||||
{...item}
|
||||
/>
|
||||
) :
|
||||
null;
|
||||
})
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
}
|
||||
</Scroller>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectBookModalContent.propTypes = {
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
onBookSelect: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default SelectBookModalContent;
|
||||
@@ -0,0 +1,104 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import {
|
||||
updateInteractiveImportItem,
|
||||
saveInteractiveImportItem,
|
||||
fetchInteractiveImportBooks,
|
||||
setInteractiveImportBooksSort,
|
||||
clearInteractiveImportBooks
|
||||
} from 'Store/Actions/interactiveImportActions';
|
||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||
import SelectBookModalContent from './SelectBookModalContent';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createClientSideCollectionSelector('interactiveImport.books'),
|
||||
(books) => {
|
||||
return books;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchInteractiveImportBooks,
|
||||
setInteractiveImportBooksSort,
|
||||
clearInteractiveImportBooks,
|
||||
updateInteractiveImportItem,
|
||||
saveInteractiveImportItem
|
||||
};
|
||||
|
||||
class SelectBookModalContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
authorId
|
||||
} = this.props;
|
||||
|
||||
this.props.fetchInteractiveImportBooks({ authorId });
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// This clears the books for the queue and hides the queue
|
||||
// We'll need another place to store books for manual import
|
||||
this.props.clearInteractiveImportBooks();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onSortPress = (sortKey, sortDirection) => {
|
||||
this.props.setInteractiveImportBooksSort({ sortKey, sortDirection });
|
||||
}
|
||||
|
||||
onBookSelect = (bookId) => {
|
||||
const book = _.find(this.props.items, { id: bookId });
|
||||
|
||||
const ids = this.props.ids;
|
||||
|
||||
ids.forEach((id) => {
|
||||
this.props.updateInteractiveImportItem({
|
||||
id,
|
||||
book,
|
||||
bookReleaseId: undefined,
|
||||
rejections: []
|
||||
});
|
||||
});
|
||||
|
||||
this.props.saveInteractiveImportItem({ id: ids });
|
||||
|
||||
this.props.onModalClose(true);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<SelectBookModalContent
|
||||
{...this.props}
|
||||
onSortPress={this.onSortPress}
|
||||
onBookSelect={this.onBookSelect}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectBookModalContentConnector.propTypes = {
|
||||
ids: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
authorId: PropTypes.number.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
fetchInteractiveImportBooks: PropTypes.func.isRequired,
|
||||
setInteractiveImportBooksSort: PropTypes.func.isRequired,
|
||||
clearInteractiveImportBooks: PropTypes.func.isRequired,
|
||||
saveInteractiveImportItem: PropTypes.func.isRequired,
|
||||
updateInteractiveImportItem: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(SelectBookModalContentConnector);
|
||||
@@ -0,0 +1,3 @@
|
||||
.bookRow {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { kinds, sizes } from 'Helpers/Props';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||
import Label from 'Components/Label';
|
||||
import styles from './SelectBookRow.css';
|
||||
|
||||
function getBookCountKind(monitored, bookFileCount, bookCount) {
|
||||
if (bookFileCount === bookCount && bookCount > 0) {
|
||||
return kinds.SUCCESS;
|
||||
}
|
||||
|
||||
if (!monitored) {
|
||||
return kinds.WARNING;
|
||||
}
|
||||
|
||||
return kinds.DANGER;
|
||||
}
|
||||
|
||||
class SelectBookRow extends Component {
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onPress = () => {
|
||||
this.props.onBookSelect(this.props.id);
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
title,
|
||||
disambiguation,
|
||||
bookType,
|
||||
releaseDate,
|
||||
statistics,
|
||||
monitored,
|
||||
columns
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
bookCount,
|
||||
bookFileCount,
|
||||
totalBookCount
|
||||
} = statistics;
|
||||
|
||||
const extendedTitle = disambiguation ? `${title} (${disambiguation})` : title;
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
onClick={this.onPress}
|
||||
className={styles.bookRow}
|
||||
>
|
||||
{
|
||||
columns.map((column) => {
|
||||
const {
|
||||
name,
|
||||
isVisible
|
||||
} = column;
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (name === 'title') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
{extendedTitle}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'bookType') {
|
||||
return (
|
||||
<TableRowCell key={name}>
|
||||
{bookType}
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'releaseDate') {
|
||||
return (
|
||||
<RelativeDateCellConnector
|
||||
key={name}
|
||||
date={releaseDate}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (name === 'status') {
|
||||
return (
|
||||
<TableRowCell
|
||||
key={name}
|
||||
>
|
||||
<Label
|
||||
title={`${totalBookCount} books total. ${bookFileCount} books with files.`}
|
||||
kind={getBookCountKind(monitored, bookFileCount, bookCount)}
|
||||
size={sizes.MEDIUM}
|
||||
>
|
||||
{
|
||||
<span>{bookFileCount} / {bookCount}</span>
|
||||
}
|
||||
</Label>
|
||||
</TableRowCell>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
}
|
||||
</TableRow>
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
SelectBookRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
disambiguation: PropTypes.string.isRequired,
|
||||
bookType: PropTypes.string.isRequired,
|
||||
releaseDate: PropTypes.string.isRequired,
|
||||
onBookSelect: PropTypes.func.isRequired,
|
||||
statistics: PropTypes.object.isRequired,
|
||||
monitored: PropTypes.bool.isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired
|
||||
};
|
||||
|
||||
SelectBookRow.defaultProps = {
|
||||
statistics: {
|
||||
bookCount: 0,
|
||||
bookFileCount: 0
|
||||
}
|
||||
};
|
||||
|
||||
export default SelectBookRow;
|
||||
Reference in New Issue
Block a user