mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-25 22:36:59 -04:00
Renames in Frontend
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { authorHistoryMarkAsFailed, clearAuthorHistory, fetchAuthorHistory } from 'Store/Actions/authorHistoryActions';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.authorHistory,
|
||||
(authorHistory) => {
|
||||
return authorHistory;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchAuthorHistory,
|
||||
clearAuthorHistory,
|
||||
authorHistoryMarkAsFailed
|
||||
};
|
||||
|
||||
class AuthorHistoryContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
authorId,
|
||||
bookId
|
||||
} = this.props;
|
||||
|
||||
this.props.fetchAuthorHistory({
|
||||
authorId,
|
||||
bookId
|
||||
});
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.clearAuthorHistory();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onMarkAsFailedPress = (historyId) => {
|
||||
const {
|
||||
authorId,
|
||||
bookId
|
||||
} = this.props;
|
||||
|
||||
this.props.authorHistoryMarkAsFailed({
|
||||
historyId,
|
||||
authorId,
|
||||
bookId
|
||||
});
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
component: ViewComponent,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ViewComponent
|
||||
{...otherProps}
|
||||
onMarkAsFailedPress={this.onMarkAsFailedPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AuthorHistoryContentConnector.propTypes = {
|
||||
component: PropTypes.elementType.isRequired,
|
||||
authorId: PropTypes.number.isRequired,
|
||||
bookId: PropTypes.number,
|
||||
fetchAuthorHistory: PropTypes.func.isRequired,
|
||||
clearAuthorHistory: PropTypes.func.isRequired,
|
||||
authorHistoryMarkAsFailed: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorHistoryContentConnector);
|
||||
@@ -0,0 +1,33 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import AuthorHistoryContentConnector from './AuthorHistoryContentConnector';
|
||||
import AuthorHistoryModalContent from './AuthorHistoryModalContent';
|
||||
|
||||
function AuthorHistoryModal(props) {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
<AuthorHistoryContentConnector
|
||||
component={AuthorHistoryModalContent}
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
AuthorHistoryModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AuthorHistoryModal;
|
||||
@@ -0,0 +1,46 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Button from 'Components/Link/Button';
|
||||
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 AuthorHistoryTableContent from './AuthorHistoryTableContent';
|
||||
|
||||
class AuthorHistoryModalContent extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
onModalClose
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
History
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<AuthorHistoryTableContent
|
||||
{...this.props}
|
||||
/>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onPress={onModalClose}>
|
||||
Close
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AuthorHistoryModalContent.propTypes = {
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AuthorHistoryModalContent;
|
||||
@@ -0,0 +1,6 @@
|
||||
.details,
|
||||
.actions {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 65px;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
|
||||
import Icon from 'Components/Icon';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import BookQuality from 'Book/BookQuality';
|
||||
import HistoryDetailsConnector from 'Activity/History/Details/HistoryDetailsConnector';
|
||||
import HistoryEventTypeCell from 'Activity/History/HistoryEventTypeCell';
|
||||
import styles from './AuthorHistoryRow.css';
|
||||
|
||||
function getTitle(eventType) {
|
||||
switch (eventType) {
|
||||
case 'grabbed':
|
||||
return 'Grabbed';
|
||||
case 'downloadImported':
|
||||
return 'Download Completed';
|
||||
case 'bookFileImported':
|
||||
return 'Book Imported';
|
||||
case 'downloadFailed':
|
||||
return 'Download Failed';
|
||||
case 'bookFileDeleted':
|
||||
return 'Book File Deleted';
|
||||
case 'bookFileRenamed':
|
||||
return 'Book File Renamed';
|
||||
case 'bookFileRetagged':
|
||||
return 'Book File Tags Updated';
|
||||
case 'bookImportIncomplete':
|
||||
return 'Book Import Incomplete';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
class AuthorHistoryRow extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
isMarkAsFailedModalOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onMarkAsFailedPress = () => {
|
||||
this.setState({ isMarkAsFailedModalOpen: true });
|
||||
}
|
||||
|
||||
onConfirmMarkAsFailed = () => {
|
||||
this.props.onMarkAsFailedPress(this.props.id);
|
||||
this.setState({ isMarkAsFailedModalOpen: false });
|
||||
}
|
||||
|
||||
onMarkAsFailedModalClose = () => {
|
||||
this.setState({ isMarkAsFailedModalOpen: false });
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
eventType,
|
||||
sourceTitle,
|
||||
quality,
|
||||
qualityCutoffNotMet,
|
||||
date,
|
||||
data,
|
||||
book
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
isMarkAsFailedModalOpen
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<HistoryEventTypeCell
|
||||
eventType={eventType}
|
||||
data={data}
|
||||
/>
|
||||
|
||||
<TableRowCell key={name}>
|
||||
{book.title}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
{sourceTitle}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
<BookQuality
|
||||
quality={quality}
|
||||
isCutoffNotMet={qualityCutoffNotMet}
|
||||
/>
|
||||
</TableRowCell>
|
||||
|
||||
<RelativeDateCellConnector
|
||||
date={date}
|
||||
/>
|
||||
|
||||
<TableRowCell className={styles.details}>
|
||||
<Popover
|
||||
anchor={
|
||||
<Icon
|
||||
name={icons.INFO}
|
||||
/>
|
||||
}
|
||||
title={getTitle(eventType)}
|
||||
body={
|
||||
<HistoryDetailsConnector
|
||||
eventType={eventType}
|
||||
sourceTitle={sourceTitle}
|
||||
data={data}
|
||||
/>
|
||||
}
|
||||
position={tooltipPositions.LEFT}
|
||||
/>
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.actions}>
|
||||
{
|
||||
eventType === 'grabbed' &&
|
||||
<IconButton
|
||||
title="Mark as failed"
|
||||
name={icons.REMOVE}
|
||||
onPress={this.onMarkAsFailedPress}
|
||||
/>
|
||||
}
|
||||
</TableRowCell>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isMarkAsFailedModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Mark as Failed"
|
||||
message={`Are you sure you want to mark '${sourceTitle}' as failed?`}
|
||||
confirmLabel="Mark as Failed"
|
||||
onConfirm={this.onConfirmMarkAsFailed}
|
||||
onCancel={this.onMarkAsFailedModalClose}
|
||||
/>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AuthorHistoryRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
eventType: PropTypes.string.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
date: PropTypes.string.isRequired,
|
||||
data: PropTypes.object.isRequired,
|
||||
fullAuthor: PropTypes.bool.isRequired,
|
||||
author: PropTypes.object.isRequired,
|
||||
book: PropTypes.object.isRequired,
|
||||
onMarkAsFailedPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AuthorHistoryRow;
|
||||
@@ -0,0 +1,26 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchHistory, markAsFailed } from 'Store/Actions/historyActions';
|
||||
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||
import createBookSelector from 'Store/Selectors/createBookSelector';
|
||||
import AuthorHistoryRow from './AuthorHistoryRow';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createAuthorSelector(),
|
||||
createBookSelector(),
|
||||
(author, book) => {
|
||||
return {
|
||||
author,
|
||||
book
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
fetchHistory,
|
||||
markAsFailed
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorHistoryRow);
|
||||
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
import AuthorHistoryContentConnector from 'Author/History/AuthorHistoryContentConnector';
|
||||
import AuthorHistoryTableContent from 'Author/History/AuthorHistoryTableContent';
|
||||
|
||||
function AuthorHistoryTable(props) {
|
||||
const {
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<AuthorHistoryContentConnector
|
||||
component={AuthorHistoryTableContent}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
AuthorHistoryTable.propTypes = {
|
||||
};
|
||||
|
||||
export default AuthorHistoryTable;
|
||||
@@ -0,0 +1,113 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import AuthorHistoryRowConnector from './AuthorHistoryRowConnector';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'eventType',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'book',
|
||||
label: 'Book',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'sourceTitle',
|
||||
label: 'Source Title',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'quality',
|
||||
label: 'Quality',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'date',
|
||||
label: 'Date',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'details',
|
||||
label: 'Details',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
label: 'Actions',
|
||||
isVisible: true
|
||||
}
|
||||
];
|
||||
|
||||
class AuthorHistoryTableContent extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
bookId,
|
||||
isFetching,
|
||||
isPopulated,
|
||||
error,
|
||||
items,
|
||||
onMarkAsFailedPress
|
||||
} = this.props;
|
||||
|
||||
const fullAuthor = bookId == null;
|
||||
const hasItems = !!items.length;
|
||||
|
||||
return (
|
||||
<>
|
||||
{
|
||||
isFetching &&
|
||||
<LoadingIndicator />
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>Unable to load history.</div>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && !hasItems && !error &&
|
||||
<div>No history.</div>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && hasItems && !error &&
|
||||
<Table columns={columns}>
|
||||
<TableBody>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<AuthorHistoryRowConnector
|
||||
key={item.id}
|
||||
fullAuthor={fullAuthor}
|
||||
{...item}
|
||||
onMarkAsFailedPress={onMarkAsFailedPress}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</TableBody>
|
||||
</Table>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AuthorHistoryTableContent.propTypes = {
|
||||
bookId: PropTypes.number,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onMarkAsFailedPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default AuthorHistoryTableContent;
|
||||
Reference in New Issue
Block a user