mirror of
https://github.com/fergalmoran/Readarr.git
synced 2025-12-22 09:29:59 +00:00
Renames in Frontend
This commit is contained in:
@@ -6,8 +6,8 @@ import IconButton from 'Components/Link/IconButton';
|
|||||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||||
import TableRow from 'Components/Table/TableRow';
|
import TableRow from 'Components/Table/TableRow';
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
import TrackQuality from 'Album/TrackQuality';
|
import BookQuality from 'Book/BookQuality';
|
||||||
import ArtistNameLink from 'Artist/ArtistNameLink';
|
import AuthorNameLink from 'Author/AuthorNameLink';
|
||||||
import BlacklistDetailsModal from './BlacklistDetailsModal';
|
import BlacklistDetailsModal from './BlacklistDetailsModal';
|
||||||
import styles from './BlacklistRow.css';
|
import styles from './BlacklistRow.css';
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ class BlacklistRow extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
artist,
|
author,
|
||||||
sourceTitle,
|
sourceTitle,
|
||||||
quality,
|
quality,
|
||||||
date,
|
date,
|
||||||
@@ -51,7 +51,7 @@ class BlacklistRow extends Component {
|
|||||||
onRemovePress
|
onRemovePress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!artist) {
|
if (!author) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,9 +71,9 @@ class BlacklistRow extends Component {
|
|||||||
if (name === 'authors.sortName') {
|
if (name === 'authors.sortName') {
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
<ArtistNameLink
|
<AuthorNameLink
|
||||||
titleSlug={artist.titleSlug}
|
titleSlug={author.titleSlug}
|
||||||
artistName={artist.artistName}
|
authorName={author.authorName}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
);
|
);
|
||||||
@@ -93,7 +93,7 @@ class BlacklistRow extends Component {
|
|||||||
key={name}
|
key={name}
|
||||||
className={styles.quality}
|
className={styles.quality}
|
||||||
>
|
>
|
||||||
<TrackQuality
|
<BookQuality
|
||||||
quality={quality}
|
quality={quality}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
@@ -161,7 +161,7 @@ class BlacklistRow extends Component {
|
|||||||
|
|
||||||
BlacklistRow.propTypes = {
|
BlacklistRow.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
artist: PropTypes.object.isRequired,
|
author: PropTypes.object.isRequired,
|
||||||
sourceTitle: PropTypes.string.isRequired,
|
sourceTitle: PropTypes.string.isRequired,
|
||||||
quality: PropTypes.object.isRequired,
|
quality: PropTypes.object.isRequired,
|
||||||
date: PropTypes.string.isRequired,
|
date: PropTypes.string.isRequired,
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import { removeFromBlacklist } from 'Store/Actions/blacklistActions';
|
import { removeFromBlacklist } from 'Store/Actions/blacklistActions';
|
||||||
import BlacklistRow from './BlacklistRow';
|
import BlacklistRow from './BlacklistRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
(artist) => {
|
(author) => {
|
||||||
return {
|
return {
|
||||||
artist
|
author
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -170,7 +170,7 @@ function HistoryDetails(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType === 'trackFileImported') {
|
if (eventType === 'bookFileImported') {
|
||||||
const {
|
const {
|
||||||
droppedPath,
|
droppedPath,
|
||||||
importedPath
|
importedPath
|
||||||
@@ -205,7 +205,7 @@ function HistoryDetails(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType === 'trackFileDeleted') {
|
if (eventType === 'bookFileDeleted') {
|
||||||
const {
|
const {
|
||||||
reason
|
reason
|
||||||
} = data;
|
} = data;
|
||||||
@@ -241,7 +241,7 @@ function HistoryDetails(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType === 'trackFileRenamed') {
|
if (eventType === 'bookFileRenamed') {
|
||||||
const {
|
const {
|
||||||
sourcePath,
|
sourcePath,
|
||||||
path
|
path
|
||||||
@@ -262,7 +262,7 @@ function HistoryDetails(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType === 'trackFileRetagged') {
|
if (eventType === 'bookFileRetagged') {
|
||||||
const {
|
const {
|
||||||
diff,
|
diff,
|
||||||
tagsScrubbed
|
tagsScrubbed
|
||||||
@@ -293,7 +293,7 @@ function HistoryDetails(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType === 'albumImportIncomplete') {
|
if (eventType === 'bookImportIncomplete') {
|
||||||
const {
|
const {
|
||||||
statusMessages
|
statusMessages
|
||||||
} = data;
|
} = data;
|
||||||
|
|||||||
@@ -17,16 +17,16 @@ function getHeaderTitle(eventType) {
|
|||||||
return 'Grabbed';
|
return 'Grabbed';
|
||||||
case 'downloadFailed':
|
case 'downloadFailed':
|
||||||
return 'Download Failed';
|
return 'Download Failed';
|
||||||
case 'trackFileImported':
|
case 'bookFileImported':
|
||||||
return 'Track Imported';
|
return 'Book Imported';
|
||||||
case 'trackFileDeleted':
|
case 'bookFileDeleted':
|
||||||
return 'Track File Deleted';
|
return 'Book File Deleted';
|
||||||
case 'trackFileRenamed':
|
case 'bookFileRenamed':
|
||||||
return 'Track File Renamed';
|
return 'Book File Renamed';
|
||||||
case 'trackFileRetagged':
|
case 'bookFileRetagged':
|
||||||
return 'Track File Tags Updated';
|
return 'Book File Tags Updated';
|
||||||
case 'albumImportIncomplete':
|
case 'bookImportIncomplete':
|
||||||
return 'Album Import Incomplete';
|
return 'Book Import Incomplete';
|
||||||
case 'downloadImported':
|
case 'downloadImported':
|
||||||
return 'Download Completed';
|
return 'Download Completed';
|
||||||
case 'downloadIgnored':
|
case 'downloadIgnored':
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class History extends Component {
|
|||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
// Don't update when fetching has completed if items have changed,
|
// Don't update when fetching has completed if items have changed,
|
||||||
// before albums start fetching or when albums start fetching.
|
// before books start fetching or when books start fetching.
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(
|
(
|
||||||
@@ -30,7 +30,7 @@ class History extends Component {
|
|||||||
nextProps.isPopulated &&
|
nextProps.isPopulated &&
|
||||||
hasDifferentItems(this.props.items, nextProps.items)
|
hasDifferentItems(this.props.items, nextProps.items)
|
||||||
) ||
|
) ||
|
||||||
(!this.props.isAlbumsFetching && nextProps.isAlbumsFetching)
|
(!this.props.isBooksFetching && nextProps.isBooksFetching)
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -51,17 +51,17 @@ class History extends Component {
|
|||||||
selectedFilterKey,
|
selectedFilterKey,
|
||||||
filters,
|
filters,
|
||||||
totalRecords,
|
totalRecords,
|
||||||
isAlbumsFetching,
|
isBooksFetching,
|
||||||
isAlbumsPopulated,
|
isBooksPopulated,
|
||||||
albumsError,
|
booksError,
|
||||||
onFilterSelect,
|
onFilterSelect,
|
||||||
onFirstPagePress,
|
onFirstPagePress,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const isFetchingAny = isFetching || isAlbumsFetching;
|
const isFetchingAny = isFetching || isBooksFetching;
|
||||||
const isAllPopulated = isPopulated && (isAlbumsPopulated || !items.length);
|
const isAllPopulated = isPopulated && (isBooksPopulated || !items.length);
|
||||||
const hasError = error || albumsError;
|
const hasError = error || booksError;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent title="History">
|
<PageContent title="History">
|
||||||
@@ -109,7 +109,7 @@ class History extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// If history isPopulated and it's empty show no history found and don't
|
// If history isPopulated and it's empty show no history found and don't
|
||||||
// wait for the albums to populate because they are never coming.
|
// wait for the books to populate because they are never coming.
|
||||||
|
|
||||||
isPopulated && !hasError && !items.length &&
|
isPopulated && !hasError && !items.length &&
|
||||||
<div>
|
<div>
|
||||||
@@ -162,9 +162,9 @@ History.propTypes = {
|
|||||||
selectedFilterKey: PropTypes.string.isRequired,
|
selectedFilterKey: PropTypes.string.isRequired,
|
||||||
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
filters: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
totalRecords: PropTypes.number,
|
totalRecords: PropTypes.number,
|
||||||
isAlbumsFetching: PropTypes.bool.isRequired,
|
isBooksFetching: PropTypes.bool.isRequired,
|
||||||
isAlbumsPopulated: PropTypes.bool.isRequired,
|
isBooksPopulated: PropTypes.bool.isRequired,
|
||||||
albumsError: PropTypes.object,
|
booksError: PropTypes.object,
|
||||||
onFilterSelect: PropTypes.func.isRequired,
|
onFilterSelect: PropTypes.func.isRequired,
|
||||||
onFirstPagePress: PropTypes.func.isRequired
|
onFirstPagePress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,23 +7,18 @@ import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
|||||||
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
|
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
|
||||||
import withCurrentPage from 'Components/withCurrentPage';
|
import withCurrentPage from 'Components/withCurrentPage';
|
||||||
import * as historyActions from 'Store/Actions/historyActions';
|
import * as historyActions from 'Store/Actions/historyActions';
|
||||||
import { fetchAlbums, clearAlbums } from 'Store/Actions/albumActions';
|
import { fetchBooks, clearBooks } from 'Store/Actions/bookActions';
|
||||||
import { fetchTracks, clearTracks } from 'Store/Actions/trackActions';
|
|
||||||
import History from './History';
|
import History from './History';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.history,
|
(state) => state.history,
|
||||||
(state) => state.albums,
|
(state) => state.books,
|
||||||
(state) => state.tracks,
|
(history, books) => {
|
||||||
(history, albums, tracks) => {
|
|
||||||
return {
|
return {
|
||||||
isAlbumsFetching: albums.isFetching,
|
isBooksFetching: books.isFetching,
|
||||||
isAlbumsPopulated: albums.isPopulated,
|
isBooksPopulated: books.isPopulated,
|
||||||
albumsError: albums.error,
|
booksError: books.error,
|
||||||
isTracksFetching: tracks.isFetching,
|
|
||||||
isTracksPopulated: tracks.isPopulated,
|
|
||||||
tracksError: tracks.error,
|
|
||||||
...history
|
...history
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -32,10 +27,8 @@ function createMapStateToProps() {
|
|||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
...historyActions,
|
...historyActions,
|
||||||
fetchAlbums,
|
fetchBooks,
|
||||||
clearAlbums,
|
clearBooks
|
||||||
fetchTracks,
|
|
||||||
clearTracks
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HistoryConnector extends Component {
|
class HistoryConnector extends Component {
|
||||||
@@ -62,16 +55,10 @@ class HistoryConnector extends Component {
|
|||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
if (hasDifferentItems(prevProps.items, this.props.items)) {
|
if (hasDifferentItems(prevProps.items, this.props.items)) {
|
||||||
const bookIds = selectUniqueIds(this.props.items, 'bookId');
|
const bookIds = selectUniqueIds(this.props.items, 'bookId');
|
||||||
const trackIds = selectUniqueIds(this.props.items, 'trackId');
|
|
||||||
if (bookIds.length) {
|
if (bookIds.length) {
|
||||||
this.props.fetchAlbums({ bookIds });
|
this.props.fetchBooks({ bookIds });
|
||||||
} else {
|
} else {
|
||||||
this.props.clearAlbums();
|
this.props.clearBooks();
|
||||||
}
|
|
||||||
if (trackIds.length) {
|
|
||||||
this.props.fetchTracks({ trackIds });
|
|
||||||
} else {
|
|
||||||
this.props.clearTracks();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,8 +66,7 @@ class HistoryConnector extends Component {
|
|||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
unregisterPagePopulator(this.repopulate);
|
unregisterPagePopulator(this.repopulate);
|
||||||
this.props.clearHistory();
|
this.props.clearHistory();
|
||||||
this.props.clearAlbums();
|
this.props.clearBooks();
|
||||||
this.props.clearTracks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -162,10 +148,8 @@ HistoryConnector.propTypes = {
|
|||||||
setHistoryFilter: PropTypes.func.isRequired,
|
setHistoryFilter: PropTypes.func.isRequired,
|
||||||
setHistoryTableOption: PropTypes.func.isRequired,
|
setHistoryTableOption: PropTypes.func.isRequired,
|
||||||
clearHistory: PropTypes.func.isRequired,
|
clearHistory: PropTypes.func.isRequired,
|
||||||
fetchAlbums: PropTypes.func.isRequired,
|
fetchBooks: PropTypes.func.isRequired,
|
||||||
clearAlbums: PropTypes.func.isRequired,
|
clearBooks: PropTypes.func.isRequired
|
||||||
fetchTracks: PropTypes.func.isRequired,
|
|
||||||
clearTracks: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withCurrentPage(
|
export default withCurrentPage(
|
||||||
|
|||||||
@@ -9,19 +9,19 @@ function getIconName(eventType) {
|
|||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case 'grabbed':
|
case 'grabbed':
|
||||||
return icons.DOWNLOADING;
|
return icons.DOWNLOADING;
|
||||||
case 'artistFolderImported':
|
case 'authorFolderImported':
|
||||||
return icons.DRIVE;
|
return icons.DRIVE;
|
||||||
case 'trackFileImported':
|
case 'bookFileImported':
|
||||||
return icons.DOWNLOADED;
|
return icons.DOWNLOADED;
|
||||||
case 'downloadFailed':
|
case 'downloadFailed':
|
||||||
return icons.DOWNLOADING;
|
return icons.DOWNLOADING;
|
||||||
case 'trackFileDeleted':
|
case 'bookFileDeleted':
|
||||||
return icons.DELETE;
|
return icons.DELETE;
|
||||||
case 'trackFileRenamed':
|
case 'bookFileRenamed':
|
||||||
return icons.ORGANIZE;
|
return icons.ORGANIZE;
|
||||||
case 'trackFileRetagged':
|
case 'bookFileRetagged':
|
||||||
return icons.RETAG;
|
return icons.RETAG;
|
||||||
case 'albumImportIncomplete':
|
case 'bookImportIncomplete':
|
||||||
return icons.DOWNLOADED;
|
return icons.DOWNLOADED;
|
||||||
case 'downloadImported':
|
case 'downloadImported':
|
||||||
return icons.DOWNLOADED;
|
return icons.DOWNLOADED;
|
||||||
@@ -36,7 +36,7 @@ function getIconKind(eventType) {
|
|||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case 'downloadFailed':
|
case 'downloadFailed':
|
||||||
return kinds.DANGER;
|
return kinds.DANGER;
|
||||||
case 'albumImportIncomplete':
|
case 'bookImportIncomplete':
|
||||||
return kinds.WARNING;
|
return kinds.WARNING;
|
||||||
default:
|
default:
|
||||||
return kinds.DEFAULT;
|
return kinds.DEFAULT;
|
||||||
@@ -46,25 +46,25 @@ function getIconKind(eventType) {
|
|||||||
function getTooltip(eventType, data) {
|
function getTooltip(eventType, data) {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
case 'grabbed':
|
case 'grabbed':
|
||||||
return `Album grabbed from ${data.indexer} and sent to ${data.downloadClient}`;
|
return `Book grabbed from ${data.indexer} and sent to ${data.downloadClient}`;
|
||||||
case 'artistFolderImported':
|
case 'authorFolderImported':
|
||||||
return 'Track imported from artist folder';
|
return 'Book imported from author folder';
|
||||||
case 'trackFileImported':
|
case 'bookFileImported':
|
||||||
return 'Track downloaded successfully and picked up from download client';
|
return 'Book downloaded successfully and picked up from download client';
|
||||||
case 'downloadFailed':
|
case 'downloadFailed':
|
||||||
return 'Album download failed';
|
return 'Book download failed';
|
||||||
case 'trackFileDeleted':
|
case 'bookFileDeleted':
|
||||||
return 'Track file deleted';
|
return 'Book file deleted';
|
||||||
case 'trackFileRenamed':
|
case 'bookFileRenamed':
|
||||||
return 'Track file renamed';
|
return 'Book file renamed';
|
||||||
case 'trackFileRetagged':
|
case 'bookFileRetagged':
|
||||||
return 'Track file tags updated';
|
return 'Book file tags updated';
|
||||||
case 'albumImportIncomplete':
|
case 'bookImportIncomplete':
|
||||||
return 'Files downloaded but not all could be imported';
|
return 'Files downloaded but not all could be imported';
|
||||||
case 'downloadImported':
|
case 'downloadImported':
|
||||||
return 'Download completed and successfully imported';
|
return 'Download completed and successfully imported';
|
||||||
case 'downloadIgnored':
|
case 'downloadIgnored':
|
||||||
return 'Album Download Ignored';
|
return 'Book Download Ignored';
|
||||||
default:
|
default:
|
||||||
return 'Unknown event';
|
return 'Unknown event';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import IconButton from 'Components/Link/IconButton';
|
|||||||
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
|
||||||
import TableRow from 'Components/Table/TableRow';
|
import TableRow from 'Components/Table/TableRow';
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
import AlbumTitleLink from 'Album/AlbumTitleLink';
|
import BookTitleLink from 'Book/BookTitleLink';
|
||||||
import TrackQuality from 'Album/TrackQuality';
|
import BookQuality from 'Book/BookQuality';
|
||||||
import ArtistNameLink from 'Artist/ArtistNameLink';
|
import AuthorNameLink from 'Author/AuthorNameLink';
|
||||||
import HistoryEventTypeCell from './HistoryEventTypeCell';
|
import HistoryEventTypeCell from './HistoryEventTypeCell';
|
||||||
import HistoryDetailsModal from './Details/HistoryDetailsModal';
|
import HistoryDetailsModal from './Details/HistoryDetailsModal';
|
||||||
import styles from './HistoryRow.css';
|
import styles from './HistoryRow.css';
|
||||||
@@ -51,8 +51,8 @@ class HistoryRow extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
artist,
|
author,
|
||||||
album,
|
book,
|
||||||
quality,
|
quality,
|
||||||
qualityCutoffNotMet,
|
qualityCutoffNotMet,
|
||||||
eventType,
|
eventType,
|
||||||
@@ -66,7 +66,7 @@ class HistoryRow extends Component {
|
|||||||
onMarkAsFailedPress
|
onMarkAsFailedPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (!artist || !album) {
|
if (!author || !book) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,9 +96,9 @@ class HistoryRow extends Component {
|
|||||||
if (name === 'authors.sortName') {
|
if (name === 'authors.sortName') {
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
<ArtistNameLink
|
<AuthorNameLink
|
||||||
titleSlug={artist.titleSlug}
|
titleSlug={author.titleSlug}
|
||||||
artistName={artist.artistName}
|
authorName={author.authorName}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
);
|
);
|
||||||
@@ -107,10 +107,10 @@ class HistoryRow extends Component {
|
|||||||
if (name === 'books.title') {
|
if (name === 'books.title') {
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
<AlbumTitleLink
|
<BookTitleLink
|
||||||
titleSlug={album.titleSlug}
|
titleSlug={book.titleSlug}
|
||||||
title={album.title}
|
title={book.title}
|
||||||
disambiguation={album.disambiguation}
|
disambiguation={book.disambiguation}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
);
|
);
|
||||||
@@ -119,7 +119,7 @@ class HistoryRow extends Component {
|
|||||||
if (name === 'quality') {
|
if (name === 'quality') {
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
<TrackQuality
|
<BookQuality
|
||||||
quality={quality}
|
quality={quality}
|
||||||
isCutoffMet={qualityCutoffNotMet}
|
isCutoffMet={qualityCutoffNotMet}
|
||||||
/>
|
/>
|
||||||
@@ -206,8 +206,8 @@ class HistoryRow extends Component {
|
|||||||
|
|
||||||
HistoryRow.propTypes = {
|
HistoryRow.propTypes = {
|
||||||
bookId: PropTypes.number,
|
bookId: PropTypes.number,
|
||||||
artist: PropTypes.object.isRequired,
|
author: PropTypes.object.isRequired,
|
||||||
album: PropTypes.object,
|
book: PropTypes.object,
|
||||||
quality: PropTypes.object.isRequired,
|
quality: PropTypes.object.isRequired,
|
||||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||||
eventType: PropTypes.string.isRequired,
|
eventType: PropTypes.string.isRequired,
|
||||||
|
|||||||
@@ -3,23 +3,20 @@ import React, { Component } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { fetchHistory, markAsFailed } from 'Store/Actions/historyActions';
|
import { fetchHistory, markAsFailed } from 'Store/Actions/historyActions';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import createAlbumSelector from 'Store/Selectors/createAlbumSelector';
|
import createBookSelector from 'Store/Selectors/createBookSelector';
|
||||||
import createTrackSelector from 'Store/Selectors/createTrackSelector';
|
|
||||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||||
import HistoryRow from './HistoryRow';
|
import HistoryRow from './HistoryRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
createAlbumSelector(),
|
createBookSelector(),
|
||||||
createTrackSelector(),
|
|
||||||
createUISettingsSelector(),
|
createUISettingsSelector(),
|
||||||
(artist, album, track, uiSettings) => {
|
(author, book, uiSettings) => {
|
||||||
return {
|
return {
|
||||||
artist,
|
author,
|
||||||
album,
|
book,
|
||||||
track,
|
|
||||||
shortDateFormat: uiSettings.shortDateFormat,
|
shortDateFormat: uiSettings.shortDateFormat,
|
||||||
timeFormat: uiSettings.timeFormat
|
timeFormat: uiSettings.timeFormat
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class Queue extends Component {
|
|||||||
|
|
||||||
shouldComponentUpdate(nextProps) {
|
shouldComponentUpdate(nextProps) {
|
||||||
// Don't update when fetching has completed if items have changed,
|
// Don't update when fetching has completed if items have changed,
|
||||||
// before albums start fetching or when albums start fetching.
|
// before books start fetching or when books start fetching.
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.props.isFetching &&
|
this.props.isFetching &&
|
||||||
@@ -53,7 +53,7 @@ class Queue extends Component {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.props.isAlbumsFetching && nextProps.isAlbumsFetching) {
|
if (!this.props.isBooksFetching && nextProps.isBooksFetching) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,9 +125,9 @@ class Queue extends Component {
|
|||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
items,
|
items,
|
||||||
isAlbumsFetching,
|
isBooksFetching,
|
||||||
isAlbumsPopulated,
|
isBooksPopulated,
|
||||||
albumsError,
|
booksError,
|
||||||
columns,
|
columns,
|
||||||
totalRecords,
|
totalRecords,
|
||||||
isGrabbing,
|
isGrabbing,
|
||||||
@@ -145,9 +145,9 @@ class Queue extends Component {
|
|||||||
isPendingSelected
|
isPendingSelected
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const isRefreshing = isFetching || isAlbumsFetching || isRefreshMonitoredDownloadsExecuting;
|
const isRefreshing = isFetching || isBooksFetching || isRefreshMonitoredDownloadsExecuting;
|
||||||
const isAllPopulated = isPopulated && (isAlbumsPopulated || !items.length || items.every((e) => !e.bookId));
|
const isAllPopulated = isPopulated && (isBooksPopulated || !items.length || items.every((e) => !e.bookId));
|
||||||
const hasError = error || albumsError;
|
const hasError = error || booksError;
|
||||||
const selectedIds = this.getSelectedIds();
|
const selectedIds = this.getSelectedIds();
|
||||||
const selectedCount = selectedIds.length;
|
const selectedCount = selectedIds.length;
|
||||||
const disableSelectedActions = selectedCount === 0;
|
const disableSelectedActions = selectedCount === 0;
|
||||||
@@ -280,9 +280,9 @@ Queue.propTypes = {
|
|||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
isAlbumsFetching: PropTypes.bool.isRequired,
|
isBooksFetching: PropTypes.bool.isRequired,
|
||||||
isAlbumsPopulated: PropTypes.bool.isRequired,
|
isBooksPopulated: PropTypes.bool.isRequired,
|
||||||
albumsError: PropTypes.object,
|
booksError: PropTypes.object,
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
totalRecords: PropTypes.number,
|
totalRecords: PropTypes.number,
|
||||||
isGrabbing: PropTypes.bool.isRequired,
|
isGrabbing: PropTypes.bool.isRequired,
|
||||||
|
|||||||
@@ -9,21 +9,21 @@ import withCurrentPage from 'Components/withCurrentPage';
|
|||||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as queueActions from 'Store/Actions/queueActions';
|
import * as queueActions from 'Store/Actions/queueActions';
|
||||||
import { fetchAlbums, clearAlbums } from 'Store/Actions/albumActions';
|
import { fetchBooks, clearBooks } from 'Store/Actions/bookActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import Queue from './Queue';
|
import Queue from './Queue';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.albums,
|
(state) => state.books,
|
||||||
(state) => state.queue.options,
|
(state) => state.queue.options,
|
||||||
(state) => state.queue.paged,
|
(state) => state.queue.paged,
|
||||||
createCommandExecutingSelector(commandNames.REFRESH_MONITORED_DOWNLOADS),
|
createCommandExecutingSelector(commandNames.REFRESH_MONITORED_DOWNLOADS),
|
||||||
(albums, options, queue, isRefreshMonitoredDownloadsExecuting) => {
|
(books, options, queue, isRefreshMonitoredDownloadsExecuting) => {
|
||||||
return {
|
return {
|
||||||
isAlbumsFetching: albums.isFetching,
|
isBooksFetching: books.isFetching,
|
||||||
isAlbumsPopulated: albums.isPopulated,
|
isBooksPopulated: books.isPopulated,
|
||||||
albumsError: albums.error,
|
booksError: books.error,
|
||||||
isRefreshMonitoredDownloadsExecuting,
|
isRefreshMonitoredDownloadsExecuting,
|
||||||
...options,
|
...options,
|
||||||
...queue
|
...queue
|
||||||
@@ -34,8 +34,8 @@ function createMapStateToProps() {
|
|||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
...queueActions,
|
...queueActions,
|
||||||
fetchAlbums,
|
fetchBooks,
|
||||||
clearAlbums,
|
clearBooks,
|
||||||
executeCommand
|
executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,15 +65,15 @@ class QueueConnector extends Component {
|
|||||||
const bookIds = selectUniqueIds(this.props.items, 'bookId');
|
const bookIds = selectUniqueIds(this.props.items, 'bookId');
|
||||||
|
|
||||||
if (bookIds.length) {
|
if (bookIds.length) {
|
||||||
this.props.fetchAlbums({ bookIds });
|
this.props.fetchBooks({ bookIds });
|
||||||
} else {
|
} else {
|
||||||
this.props.clearAlbums();
|
this.props.clearBooks();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.props.includeUnknownArtistItems !==
|
this.props.includeUnknownAuthorItems !==
|
||||||
prevProps.includeUnknownArtistItems
|
prevProps.includeUnknownAuthorItems
|
||||||
) {
|
) {
|
||||||
this.repopulate();
|
this.repopulate();
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ class QueueConnector extends Component {
|
|||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
unregisterPagePopulator(this.repopulate);
|
unregisterPagePopulator(this.repopulate);
|
||||||
this.props.clearQueue();
|
this.props.clearQueue();
|
||||||
this.props.clearAlbums();
|
this.props.clearBooks();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -166,7 +166,7 @@ class QueueConnector extends Component {
|
|||||||
QueueConnector.propTypes = {
|
QueueConnector.propTypes = {
|
||||||
useCurrentPage: PropTypes.bool.isRequired,
|
useCurrentPage: PropTypes.bool.isRequired,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
includeUnknownArtistItems: PropTypes.bool.isRequired,
|
includeUnknownAuthorItems: PropTypes.bool.isRequired,
|
||||||
fetchQueue: PropTypes.func.isRequired,
|
fetchQueue: PropTypes.func.isRequired,
|
||||||
gotoQueueFirstPage: PropTypes.func.isRequired,
|
gotoQueueFirstPage: PropTypes.func.isRequired,
|
||||||
gotoQueuePreviousPage: PropTypes.func.isRequired,
|
gotoQueuePreviousPage: PropTypes.func.isRequired,
|
||||||
@@ -178,8 +178,8 @@ QueueConnector.propTypes = {
|
|||||||
clearQueue: PropTypes.func.isRequired,
|
clearQueue: PropTypes.func.isRequired,
|
||||||
grabQueueItems: PropTypes.func.isRequired,
|
grabQueueItems: PropTypes.func.isRequired,
|
||||||
removeQueueItems: PropTypes.func.isRequired,
|
removeQueueItems: PropTypes.func.isRequired,
|
||||||
fetchAlbums: PropTypes.func.isRequired,
|
fetchBooks: PropTypes.func.isRequired,
|
||||||
clearAlbums: PropTypes.func.isRequired,
|
clearBooks: PropTypes.func.isRequired,
|
||||||
executeCommand: PropTypes.func.isRequired
|
executeCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ function QueueDetails(props) {
|
|||||||
return (
|
return (
|
||||||
<Icon
|
<Icon
|
||||||
name={icons.DOWNLOADING}
|
name={icons.DOWNLOADING}
|
||||||
title={`Album is downloading - ${progress.toFixed(1)}% ${title}`}
|
title={`Book is downloading - ${progress.toFixed(1)}% ${title}`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,18 +14,18 @@ class QueueOptions extends Component {
|
|||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
includeUnknownArtistItems: props.includeUnknownArtistItems
|
includeUnknownAuthorItems: props.includeUnknownAuthorItems
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const {
|
const {
|
||||||
includeUnknownArtistItems
|
includeUnknownAuthorItems
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (includeUnknownArtistItems !== prevProps.includeUnknownArtistItems) {
|
if (includeUnknownAuthorItems !== prevProps.includeUnknownAuthorItems) {
|
||||||
this.setState({
|
this.setState({
|
||||||
includeUnknownArtistItems
|
includeUnknownAuthorItems
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,19 +48,19 @@ class QueueOptions extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
includeUnknownArtistItems
|
includeUnknownAuthorItems
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>Show Unknown Artist Items</FormLabel>
|
<FormLabel>Show Unknown Author Items</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="includeUnknownArtistItems"
|
name="includeUnknownAuthorItems"
|
||||||
value={includeUnknownArtistItems}
|
value={includeUnknownAuthorItems}
|
||||||
helpText="Show items without a artist in the queue, this could include removed artists, movies or anything else in Readarr's category"
|
helpText="Show items without a author in the queue, this could include removed authors, movies or anything else in Readarr's category"
|
||||||
onChange={this.onOptionChange}
|
onChange={this.onOptionChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
@@ -70,7 +70,7 @@ class QueueOptions extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QueueOptions.propTypes = {
|
QueueOptions.propTypes = {
|
||||||
includeUnknownArtistItems: PropTypes.bool.isRequired,
|
includeUnknownAuthorItems: PropTypes.bool.isRequired,
|
||||||
onOptionChange: PropTypes.func.isRequired
|
onOptionChange: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
|||||||
import Icon from 'Components/Icon';
|
import Icon from 'Components/Icon';
|
||||||
import Popover from 'Components/Tooltip/Popover';
|
import Popover from 'Components/Tooltip/Popover';
|
||||||
import ProtocolLabel from 'Activity/Queue/ProtocolLabel';
|
import ProtocolLabel from 'Activity/Queue/ProtocolLabel';
|
||||||
import AlbumTitleLink from 'Album/AlbumTitleLink';
|
import BookTitleLink from 'Book/BookTitleLink';
|
||||||
import TrackQuality from 'Album/TrackQuality';
|
import BookQuality from 'Book/BookQuality';
|
||||||
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
|
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
|
||||||
import ArtistNameLink from 'Artist/ArtistNameLink';
|
import AuthorNameLink from 'Author/AuthorNameLink';
|
||||||
import QueueStatusCell from './QueueStatusCell';
|
import QueueStatusCell from './QueueStatusCell';
|
||||||
import TimeleftCell from './TimeleftCell';
|
import TimeleftCell from './TimeleftCell';
|
||||||
import RemoveQueueItemModal from './RemoveQueueItemModal';
|
import RemoveQueueItemModal from './RemoveQueueItemModal';
|
||||||
@@ -71,8 +71,8 @@ class QueueRow extends Component {
|
|||||||
trackedDownloadState,
|
trackedDownloadState,
|
||||||
statusMessages,
|
statusMessages,
|
||||||
errorMessage,
|
errorMessage,
|
||||||
artist,
|
author,
|
||||||
album,
|
book,
|
||||||
quality,
|
quality,
|
||||||
protocol,
|
protocol,
|
||||||
indexer,
|
indexer,
|
||||||
@@ -141,10 +141,10 @@ class QueueRow extends Component {
|
|||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
{
|
{
|
||||||
artist ?
|
author ?
|
||||||
<ArtistNameLink
|
<AuthorNameLink
|
||||||
titleSlug={artist.titleSlug}
|
titleSlug={author.titleSlug}
|
||||||
artistName={artist.artistName}
|
authorName={author.authorName}
|
||||||
/> :
|
/> :
|
||||||
title
|
title
|
||||||
}
|
}
|
||||||
@@ -156,11 +156,11 @@ class QueueRow extends Component {
|
|||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
{
|
{
|
||||||
album ?
|
book ?
|
||||||
<AlbumTitleLink
|
<BookTitleLink
|
||||||
titleSlug={album.titleSlug}
|
titleSlug={book.titleSlug}
|
||||||
title={album.title}
|
title={book.title}
|
||||||
disambiguation={album.disambiguation}
|
disambiguation={book.disambiguation}
|
||||||
/> :
|
/> :
|
||||||
'-'
|
'-'
|
||||||
}
|
}
|
||||||
@@ -169,11 +169,11 @@ class QueueRow extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'books.releaseDate') {
|
if (name === 'books.releaseDate') {
|
||||||
if (album) {
|
if (book) {
|
||||||
return (
|
return (
|
||||||
<RelativeDateCellConnector
|
<RelativeDateCellConnector
|
||||||
key={name}
|
key={name}
|
||||||
date={album.releaseDate}
|
date={book.releaseDate}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -188,7 +188,7 @@ class QueueRow extends Component {
|
|||||||
if (name === 'quality') {
|
if (name === 'quality') {
|
||||||
return (
|
return (
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
<TrackQuality
|
<BookQuality
|
||||||
quality={quality}
|
quality={quality}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
@@ -335,7 +335,7 @@ class QueueRow extends Component {
|
|||||||
<RemoveQueueItemModal
|
<RemoveQueueItemModal
|
||||||
isOpen={isRemoveQueueItemModalOpen}
|
isOpen={isRemoveQueueItemModalOpen}
|
||||||
sourceTitle={title}
|
sourceTitle={title}
|
||||||
canIgnore={!!(artist && album)}
|
canIgnore={!!(author && book)}
|
||||||
onRemovePress={this.onRemoveQueueItemModalConfirmed}
|
onRemovePress={this.onRemoveQueueItemModalConfirmed}
|
||||||
onModalClose={this.onRemoveQueueItemModalClose}
|
onModalClose={this.onRemoveQueueItemModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -354,8 +354,8 @@ QueueRow.propTypes = {
|
|||||||
trackedDownloadState: PropTypes.string,
|
trackedDownloadState: PropTypes.string,
|
||||||
statusMessages: PropTypes.arrayOf(PropTypes.object),
|
statusMessages: PropTypes.arrayOf(PropTypes.object),
|
||||||
errorMessage: PropTypes.string,
|
errorMessage: PropTypes.string,
|
||||||
artist: PropTypes.object,
|
author: PropTypes.object,
|
||||||
album: PropTypes.object,
|
book: PropTypes.object,
|
||||||
quality: PropTypes.object.isRequired,
|
quality: PropTypes.object.isRequired,
|
||||||
protocol: PropTypes.string.isRequired,
|
protocol: PropTypes.string.isRequired,
|
||||||
indexer: PropTypes.string,
|
indexer: PropTypes.string,
|
||||||
|
|||||||
@@ -4,25 +4,25 @@ import React, { Component } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { grabQueueItem, removeQueueItem } from 'Store/Actions/queueActions';
|
import { grabQueueItem, removeQueueItem } from 'Store/Actions/queueActions';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import createAlbumSelector from 'Store/Selectors/createAlbumSelector';
|
import createBookSelector from 'Store/Selectors/createBookSelector';
|
||||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||||
import QueueRow from './QueueRow';
|
import QueueRow from './QueueRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
createAlbumSelector(),
|
createBookSelector(),
|
||||||
createUISettingsSelector(),
|
createUISettingsSelector(),
|
||||||
(artist, album, uiSettings) => {
|
(author, book, uiSettings) => {
|
||||||
const result = _.pick(uiSettings, [
|
const result = _.pick(uiSettings, [
|
||||||
'showRelativeDates',
|
'showRelativeDates',
|
||||||
'shortDateFormat',
|
'shortDateFormat',
|
||||||
'timeFormat'
|
'timeFormat'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
result.artist = artist;
|
result.author = author;
|
||||||
result.album = album;
|
result.book = book;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ class QueueRowConnector extends Component {
|
|||||||
|
|
||||||
QueueRowConnector.propTypes = {
|
QueueRowConnector.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
album: PropTypes.object,
|
book: PropTypes.object,
|
||||||
grabQueueItem: PropTypes.func.isRequired,
|
grabQueueItem: PropTypes.func.isRequired,
|
||||||
removeQueueItem: PropTypes.func.isRequired
|
removeQueueItem: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ function createMapStateToProps() {
|
|||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.app,
|
(state) => state.app,
|
||||||
(state) => state.queue.status,
|
(state) => state.queue.status,
|
||||||
(state) => state.queue.options.includeUnknownArtistItems,
|
(state) => state.queue.options.includeUnknownAuthorItems,
|
||||||
(app, status, includeUnknownArtistItems) => {
|
(app, status, includeUnknownAuthorItems) => {
|
||||||
const {
|
const {
|
||||||
errors,
|
errors,
|
||||||
warnings,
|
warnings,
|
||||||
@@ -25,9 +25,9 @@ function createMapStateToProps() {
|
|||||||
isReconnecting: app.isReconnecting,
|
isReconnecting: app.isReconnecting,
|
||||||
isPopulated: status.isPopulated,
|
isPopulated: status.isPopulated,
|
||||||
...status.item,
|
...status.item,
|
||||||
count: includeUnknownArtistItems ? totalCount : count,
|
count: includeUnknownAuthorItems ? totalCount : count,
|
||||||
errors: includeUnknownArtistItems ? errors || unknownErrors : errors,
|
errors: includeUnknownAuthorItems ? errors || unknownErrors : errors,
|
||||||
warnings: includeUnknownArtistItems ? warnings || unknownWarnings : warnings
|
warnings: includeUnknownAuthorItems ? warnings || unknownWarnings : warnings
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
function ArtistMetadataProfilePopoverContent() {
|
function AuthorMetadataProfilePopoverContent() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
Select 'None' to only include items manually added via search or that match files on disk
|
Select 'None' to only include items manually added via search or that match files on disk
|
||||||
@@ -8,4 +8,4 @@ function ArtistMetadataProfilePopoverContent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ArtistMetadataProfilePopoverContent;
|
export default AuthorMetadataProfilePopoverContent;
|
||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||||
|
|
||||||
function ArtistMonitoringOptionsPopoverContent() {
|
function AuthorMonitoringOptionsPopoverContent() {
|
||||||
return (
|
return (
|
||||||
<DescriptionList>
|
<DescriptionList>
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
@@ -43,4 +43,4 @@ function ArtistMonitoringOptionsPopoverContent() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ArtistMonitoringOptionsPopoverContent;
|
export default AuthorMonitoringOptionsPopoverContent;
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import createArtistClientSideCollectionItemsSelector from 'Store/Selectors/createArtistClientSideCollectionItemsSelector';
|
|
||||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
|
||||||
import { setAlbumStudioSort, setAlbumStudioFilter, saveAlbumStudio } from 'Store/Actions/albumStudioActions';
|
|
||||||
import { fetchAlbums, clearAlbums } from 'Store/Actions/albumActions';
|
|
||||||
import AlbumStudio from './AlbumStudio';
|
|
||||||
|
|
||||||
function createAlbumFetchStateSelector() {
|
|
||||||
return createSelector(
|
|
||||||
(state) => state.albums.items.length,
|
|
||||||
(state) => state.albums.isFetching,
|
|
||||||
(state) => state.albums.isPopulated,
|
|
||||||
(length, isFetching, isPopulated) => {
|
|
||||||
const albumCount = (!isFetching && isPopulated) ? length : 0;
|
|
||||||
return {
|
|
||||||
albumCount,
|
|
||||||
isFetching,
|
|
||||||
isPopulated
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
createAlbumFetchStateSelector(),
|
|
||||||
createArtistClientSideCollectionItemsSelector('albumStudio'),
|
|
||||||
createDimensionsSelector(),
|
|
||||||
(albums, artist, dimensionsState) => {
|
|
||||||
const isPopulated = albums.isPopulated && artist.isPopulated;
|
|
||||||
const isFetching = artist.isFetching || albums.isFetching;
|
|
||||||
return {
|
|
||||||
...artist,
|
|
||||||
isPopulated,
|
|
||||||
isFetching,
|
|
||||||
albumCount: albums.albumCount,
|
|
||||||
isSmallScreen: dimensionsState.isSmallScreen
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
fetchAlbums,
|
|
||||||
clearAlbums,
|
|
||||||
setAlbumStudioSort,
|
|
||||||
setAlbumStudioFilter,
|
|
||||||
saveAlbumStudio
|
|
||||||
};
|
|
||||||
|
|
||||||
class AlbumStudioConnector extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.populate();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
this.unpopulate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Control
|
|
||||||
|
|
||||||
populate = () => {
|
|
||||||
this.props.fetchAlbums();
|
|
||||||
}
|
|
||||||
|
|
||||||
unpopulate = () => {
|
|
||||||
this.props.clearAlbums();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onSortPress = (sortKey) => {
|
|
||||||
this.props.setAlbumStudioSort({ sortKey });
|
|
||||||
}
|
|
||||||
|
|
||||||
onFilterSelect = (selectedFilterKey) => {
|
|
||||||
this.props.setAlbumStudioFilter({ selectedFilterKey });
|
|
||||||
}
|
|
||||||
|
|
||||||
onUpdateSelectedPress = (payload) => {
|
|
||||||
this.props.saveAlbumStudio(payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<AlbumStudio
|
|
||||||
{...this.props}
|
|
||||||
onSortPress={this.onSortPress}
|
|
||||||
onFilterSelect={this.onFilterSelect}
|
|
||||||
onUpdateSelectedPress={this.onUpdateSelectedPress}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AlbumStudioConnector.propTypes = {
|
|
||||||
setAlbumStudioSort: PropTypes.func.isRequired,
|
|
||||||
setAlbumStudioFilter: PropTypes.func.isRequired,
|
|
||||||
fetchAlbums: PropTypes.func.isRequired,
|
|
||||||
clearAlbums: PropTypes.func.isRequired,
|
|
||||||
saveAlbumStudio: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(AlbumStudioConnector);
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
|
||||||
import { toggleArtistMonitored } from 'Store/Actions/artistActions';
|
|
||||||
import { toggleAlbumsMonitored } from 'Store/Actions/albumActions';
|
|
||||||
import AlbumStudioRow from './AlbumStudioRow';
|
|
||||||
|
|
||||||
// Use a const to share the reselect cache between instances
|
|
||||||
const getAlbumMap = createSelector(
|
|
||||||
(state) => state.albums.items,
|
|
||||||
(albums) => {
|
|
||||||
return albums.reduce((acc, curr) => {
|
|
||||||
(acc[curr.authorId] = acc[curr.authorId] || []).push(curr);
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
createArtistSelector(),
|
|
||||||
getAlbumMap,
|
|
||||||
(artist, albumMap) => {
|
|
||||||
const albumsInArtist = albumMap.hasOwnProperty(artist.id) ? albumMap[artist.id] : [];
|
|
||||||
const sortedAlbums = _.orderBy(albumsInArtist, 'releaseDate', 'desc');
|
|
||||||
|
|
||||||
return {
|
|
||||||
...artist,
|
|
||||||
authorId: artist.id,
|
|
||||||
artistName: artist.artistName,
|
|
||||||
monitored: artist.monitored,
|
|
||||||
status: artist.status,
|
|
||||||
isSaving: artist.isSaving,
|
|
||||||
albums: sortedAlbums
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
toggleArtistMonitored,
|
|
||||||
toggleAlbumsMonitored
|
|
||||||
};
|
|
||||||
|
|
||||||
class AlbumStudioRowConnector extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onArtistMonitoredPress = () => {
|
|
||||||
const {
|
|
||||||
authorId,
|
|
||||||
monitored
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
this.props.toggleArtistMonitored({
|
|
||||||
authorId,
|
|
||||||
monitored: !monitored
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onAlbumMonitoredPress = (bookId, monitored) => {
|
|
||||||
const bookIds = [bookId];
|
|
||||||
this.props.toggleAlbumsMonitored({
|
|
||||||
bookIds,
|
|
||||||
monitored
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<AlbumStudioRow
|
|
||||||
{...this.props}
|
|
||||||
onArtistMonitoredPress={this.onArtistMonitoredPress}
|
|
||||||
onAlbumMonitoredPress={this.onAlbumMonitoredPress}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AlbumStudioRowConnector.propTypes = {
|
|
||||||
authorId: PropTypes.number.isRequired,
|
|
||||||
monitored: PropTypes.bool.isRequired,
|
|
||||||
toggleArtistMonitored: PropTypes.func.isRequired,
|
|
||||||
toggleAlbumsMonitored: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(AlbumStudioRowConnector);
|
|
||||||
@@ -4,13 +4,13 @@ import { Route, Redirect } from 'react-router-dom';
|
|||||||
import getPathWithUrlBase from 'Utilities/getPathWithUrlBase';
|
import getPathWithUrlBase from 'Utilities/getPathWithUrlBase';
|
||||||
import NotFound from 'Components/NotFound';
|
import NotFound from 'Components/NotFound';
|
||||||
import Switch from 'Components/Router/Switch';
|
import Switch from 'Components/Router/Switch';
|
||||||
import ArtistIndexConnector from 'Artist/Index/ArtistIndexConnector';
|
import AuthorIndexConnector from 'Author/Index/AuthorIndexConnector';
|
||||||
import AddNewItemConnector from 'Search/AddNewItemConnector';
|
import AddNewItemConnector from 'Search/AddNewItemConnector';
|
||||||
import ArtistEditorConnector from 'Artist/Editor/ArtistEditorConnector';
|
import AuthorEditorConnector from 'Author/Editor/AuthorEditorConnector';
|
||||||
import AlbumStudioConnector from 'AlbumStudio/AlbumStudioConnector';
|
import BookshelfConnector from 'Bookshelf/BookshelfConnector';
|
||||||
import UnmappedFilesTableConnector from 'UnmappedFiles/UnmappedFilesTableConnector';
|
import UnmappedFilesTableConnector from 'UnmappedFiles/UnmappedFilesTableConnector';
|
||||||
import ArtistDetailsPageConnector from 'Artist/Details/ArtistDetailsPageConnector';
|
import AuthorDetailsPageConnector from 'Author/Details/AuthorDetailsPageConnector';
|
||||||
import AlbumDetailsPageConnector from 'Album/Details/AlbumDetailsPageConnector';
|
import BookDetailsPageConnector from 'Book/Details/BookDetailsPageConnector';
|
||||||
import CalendarPageConnector from 'Calendar/CalendarPageConnector';
|
import CalendarPageConnector from 'Calendar/CalendarPageConnector';
|
||||||
import HistoryConnector from 'Activity/History/HistoryConnector';
|
import HistoryConnector from 'Activity/History/HistoryConnector';
|
||||||
import QueueConnector from 'Activity/Queue/QueueConnector';
|
import QueueConnector from 'Activity/Queue/QueueConnector';
|
||||||
@@ -44,13 +44,13 @@ function AppRoutes(props) {
|
|||||||
return (
|
return (
|
||||||
<Switch>
|
<Switch>
|
||||||
{/*
|
{/*
|
||||||
Artist
|
Author
|
||||||
*/}
|
*/}
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
exact={true}
|
exact={true}
|
||||||
path="/"
|
path="/"
|
||||||
component={ArtistIndexConnector}
|
component={AuthorIndexConnector}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -76,13 +76,13 @@ function AppRoutes(props) {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/artisteditor"
|
path="/authoreditor"
|
||||||
component={ArtistEditorConnector}
|
component={AuthorEditorConnector}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/albumstudio"
|
path="/bookshelf"
|
||||||
component={AlbumStudioConnector}
|
component={BookshelfConnector}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
@@ -92,12 +92,12 @@ function AppRoutes(props) {
|
|||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/author/:titleSlug"
|
path="/author/:titleSlug"
|
||||||
component={ArtistDetailsPageConnector}
|
component={AuthorDetailsPageConnector}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/book/:titleSlug"
|
path="/book/:titleSlug"
|
||||||
component={AlbumDetailsPageConnector}
|
component={BookDetailsPageConnector}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
/* eslint max-params: 0 */
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
|
||||||
import createTrackFileSelector from 'Store/Selectors/createTrackFileSelector';
|
|
||||||
import AlbumRow from './AlbumRow';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
createArtistSelector(),
|
|
||||||
createTrackFileSelector(),
|
|
||||||
(artist = {}, trackFile) => {
|
|
||||||
return {
|
|
||||||
artistMonitored: artist.monitored,
|
|
||||||
trackFilePath: trackFile ? trackFile.path : null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export default connect(createMapStateToProps)(AlbumRow);
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
.albumFolder {
|
|
||||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
|
||||||
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import ArtistHistoryContentConnector from 'Artist/History/ArtistHistoryContentConnector';
|
|
||||||
import ArtistHistoryTableContent from 'Artist/History/ArtistHistoryTableContent';
|
|
||||||
|
|
||||||
function ArtistHistoryTable(props) {
|
|
||||||
const {
|
|
||||||
...otherProps
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ArtistHistoryContentConnector
|
|
||||||
component={ArtistHistoryTableContent}
|
|
||||||
{...otherProps}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ArtistHistoryTable.propTypes = {
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ArtistHistoryTable;
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { icons } from 'Helpers/Props';
|
|
||||||
import IconButton from 'Components/Link/IconButton';
|
|
||||||
import SpinnerIconButton from 'Components/Link/SpinnerIconButton';
|
|
||||||
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
|
|
||||||
import EditArtistModalConnector from 'Artist/Edit/EditArtistModalConnector';
|
|
||||||
import DeleteArtistModal from 'Artist/Delete/DeleteArtistModal';
|
|
||||||
|
|
||||||
class ArtistIndexActionsCell extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
isEditArtistModalOpen: false,
|
|
||||||
isDeleteArtistModalOpen: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onEditArtistPress = () => {
|
|
||||||
this.setState({ isEditArtistModalOpen: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
onEditArtistModalClose = () => {
|
|
||||||
this.setState({ isEditArtistModalOpen: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeleteArtistPress = () => {
|
|
||||||
this.setState({
|
|
||||||
isEditArtistModalOpen: false,
|
|
||||||
isDeleteArtistModalOpen: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onDeleteArtistModalClose = () => {
|
|
||||||
this.setState({ isDeleteArtistModalOpen: false });
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
isRefreshingArtist,
|
|
||||||
onRefreshArtistPress,
|
|
||||||
...otherProps
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
|
||||||
isEditArtistModalOpen,
|
|
||||||
isDeleteArtistModalOpen
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<VirtualTableRowCell
|
|
||||||
{...otherProps}
|
|
||||||
>
|
|
||||||
<SpinnerIconButton
|
|
||||||
name={icons.REFRESH}
|
|
||||||
title="Refresh Artist"
|
|
||||||
isSpinning={isRefreshingArtist}
|
|
||||||
onPress={onRefreshArtistPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<IconButton
|
|
||||||
name={icons.EDIT}
|
|
||||||
title="Edit Artist"
|
|
||||||
onPress={this.onEditArtistPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<EditArtistModalConnector
|
|
||||||
isOpen={isEditArtistModalOpen}
|
|
||||||
authorId={id}
|
|
||||||
onModalClose={this.onEditArtistModalClose}
|
|
||||||
onDeleteArtistPress={this.onDeleteArtistPress}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DeleteArtistModal
|
|
||||||
isOpen={isDeleteArtistModalOpen}
|
|
||||||
authorId={id}
|
|
||||||
onModalClose={this.onDeleteArtistModalClose}
|
|
||||||
/>
|
|
||||||
</VirtualTableRowCell>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ArtistIndexActionsCell.propTypes = {
|
|
||||||
id: PropTypes.number.isRequired,
|
|
||||||
isRefreshingArtist: PropTypes.bool.isRequired,
|
|
||||||
onRefreshArtistPress: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ArtistIndexActionsCell;
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { connect } from 'react-redux';
|
|
||||||
import { setArtistTableOption } from 'Store/Actions/artistIndexActions';
|
|
||||||
import ArtistIndexHeader from './ArtistIndexHeader';
|
|
||||||
|
|
||||||
function createMapDispatchToProps(dispatch, props) {
|
|
||||||
return {
|
|
||||||
onTableOptionChange(payload) {
|
|
||||||
dispatch(setArtistTableOption(payload));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(undefined, createMapDispatchToProps)(ArtistIndexHeader);
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ArtistImage from './ArtistImage';
|
import AuthorImage from './AuthorImage';
|
||||||
|
|
||||||
const bannerPlaceholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+gAAAC5AgMAAADG9/24AAAADFBMVEUyMjI7Ozs1NTU4ODjgOsZvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QkRBgAc5PUQ8QAAB7tJREFUeNrtnb1rHEsMwMdjArtrUrpf3uMg2cOl+5QpXWRvjQkXlyHVK8MVYXFl3F+/GAzrNfdSuXkQnH9ie/Oqw32aFM6bkTQfd85rHrwi0qjJJql+pxlJo9FISv0XqX8mKkmSJEmSJEmSJEmSJEmSJEmS5NeVYrh7HDqJ5DeY23kQB64/u7zW91amzgXqvRqjfGYvarnfxqncuaQlf72Zxv4gSOluudOfjRy1Hzh1L+nPj+KU3jh0MWr3Sp87dDFq98An/msmg3zPW/aFR6/vRaBPglML6Mci0H0g92MYfrjvRgJ5TrDvhuFyGIZv9NdTOev93dDry1Z59mM56/2hU8WZcefFjZgVT/Z90SlEV9VKio3HeKYZLLSGII6WPP+oBv3ZwkL3iE4JG/ZRjUYb16mAripUO/c4Hl3bd/juCF19FuHeJn6nK90VBh0s3SjBvcFW/wTrvfBa118EbHY8qmMOtmgdupoKOLTvAmOH1k059LKAX+Qra/TncExH4hcBXV3Zf/+Dv5Vb43cfod/wt3PLsN5VF6HDiudt56IbB23Ql5/oZ8A7CfZWbgF61sap62XdlOZTZ2rF3c7ltNW1+f7LuDez/uc6uDfO8dwkbPXcKF8vPS9sds527pC2utH0uCb0Jmz2t8wNvN3q2jj4ntDJna94m3g4sb7HH8Gue0RH4Je8z61g4GGr79Wz1qHjbi94m/jcH1IOccsj+lt/sOFr4m0EPz+3XyNueURvSmfn+Ebx1rctMvOxU8foqOwVa+9mfdvHDH+DdYQOxAesvZslvc/wo4vQZy6eY+vdrCVrut/AyTW9CWvO3E1ra4L6i5Fxoka7MDan45vTOmx2MPGc0QH52Tb6kTPxXNGtW5/Tnl+oGP2N/dstY8eeO2M+bqM3zvVxRT+gS8Vdl5/z6CaCzfx/c41o3pP2+030UzrAHDNGv8d4FvMVAf1I4c07V/QlnNsyG9TN23ID/ZjObnO+6CZmydS+y8oG9Dfk2Gd80WcW3Rv44e5bZOLtD8EUHbRq0V0F/DAMn8fQ2UUv2UayEMxplaFvM0G7QR/ufqBcmH/gG85Z9BM8rMO5bdiUDu4ceaLvUjqWfJveQm8hpvnKFv1jOLxUTtkoBWf0nIK5Cd6wO207dAznTlmjH+K630KvuKPbOHYffJsOexykx0iWJ7pNRf+ttEXvW1U49F7ZbJ26RHSe6ehn5NRGMPBVQAfP12EQf8QZPTMxXac30M1RxtaWXLBFn3j0eRsHNIBuCycLtqfWCQZrBcZ0W+gVhXts0RtEXyit4zDOoE/N/5yNzNF3oVB0A93I6ise7bijr1XwbYiurySg7xjfpp+g375mjj5D9HYD3fr6YvkKcxU80Q8duvVt2+gjob/ljX7yFH1a80dvDfpia8GXqp3Wr1XJXevljvFt2QZ6a6tJ2Gvd2Pa8Xuu2iNB7o++r+lUJlQas93oOl04be73Ut7y1Ts4tn/0EfaxZOzcKaXIsqNiI4QtE5x7N7Z08RZ9CKpb38cWs9V26b4sDWURnr3W9foq+gpM8a3S4V+rhKUCcqrBXTufMUxU2QWUTkFtZGls3pjgnqJ4FdB1lZAd8/qMEZGRtAlJvJqONb2syzuj2CuK+1YU5reg2CzGNyqq6fpOpku8VRI7lchX+7SIy8NdQSaKn3K8bsWJOlZGBX2Ed0bUIdBXftJpzG1h2vjetWFqgHXrhczTWtx2h8llXVTytI4FHnaes0bGMqNhC1+jUXmFMx7iCaq6qy4HqxR7dFfMUtc34LQCVDPppcM13Kie5RmTGJYNUKBraDL57xEKalS0UzTgXiiqn1X3fRxR0bBf6TLEvD4aKkslTdO5F4fQUIHseo5ugfrShewbWjvsriHxT65WAByAHVCT7u0fvoKDC+rZClZyf/eSAngUTj1pfCXjshU/8smDiPTr7J374sDPDfI1Hd4cX1g874TmvRc+30U8V9+e88Ig7U6V26Ofk21rzg1ScH3Hj033bTXIZab2iGG6PdWOaQzLx7cShQ0FFfdxqlfFu2DAhxw4vf5zWV3hYZ96m47l7u0+DMAgdu1Dxbs4St+Rx6MbAwzIveLfk8Y2Y9J5HP1tij3DmjZii9lujQy9GXO/M22/5pmvUVdWiV3RkYd50zbfaI7Vb9GmDD0C4t9qLGiy+JPTVKT4A4d5gMY866N4i+p9KuUM767aavpkqLnmDDl10S8W/mSq20O3I3n8x6AXufP4tdKlxcpkZ4HN43FZ0mT3GCmicTO2ysW2uVXmFWp/yb5cdN0kHrb/ADwFN0uPW+ICOt+0SWuPjkW2tPTr+CjcSphjiGIzWodPQGwljMGj4Se/Q0bfJGH4Sj7zx6DJG3tCgo4HQoYiukDHoKB5vZdCtb9MrIUM7DyK169Zu+mEUMtQsjLJrtT7vWl2IGWXnBxjaFwFnraQBhmFs5dDqi66SNLYyGlY6XMgaVip4RG00mHh2LWwwcRhHPVsJG0cdhpDProQNIQ+j52e30kbPa19B5T64H9Wfqn0mTelB7Y04pWMFfCQf5JDTjYOTuSClu5QUSa9EyU0gf5BF7iaP2zxdq6TJjUydgxTD3aPvm5wkSZIkSZIkSZIkSZIkSZIk+Z9kv/534U2+Uyf0XwP9H83PZBlAqkdjAAAAAElFTkSuQmCC';
|
const bannerPlaceholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+gAAAC5AgMAAADG9/24AAAADFBMVEUyMjI7Ozs1NTU4ODjgOsZvAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QkRBgAc5PUQ8QAAB7tJREFUeNrtnb1rHEsMwMdjArtrUrpf3uMg2cOl+5QpXWRvjQkXlyHVK8MVYXFl3F+/GAzrNfdSuXkQnH9ie/Oqw32aFM6bkTQfd85rHrwi0qjJJql+pxlJo9FISv0XqX8mKkmSJEmSJEmSJEmSJEmSJEmS5NeVYrh7HDqJ5DeY23kQB64/u7zW91amzgXqvRqjfGYvarnfxqncuaQlf72Zxv4gSOluudOfjRy1Hzh1L+nPj+KU3jh0MWr3Sp87dDFq98An/msmg3zPW/aFR6/vRaBPglML6Mci0H0g92MYfrjvRgJ5TrDvhuFyGIZv9NdTOev93dDry1Z59mM56/2hU8WZcefFjZgVT/Z90SlEV9VKio3HeKYZLLSGII6WPP+oBv3ZwkL3iE4JG/ZRjUYb16mAripUO/c4Hl3bd/juCF19FuHeJn6nK90VBh0s3SjBvcFW/wTrvfBa118EbHY8qmMOtmgdupoKOLTvAmOH1k059LKAX+Qra/TncExH4hcBXV3Zf/+Dv5Vb43cfod/wt3PLsN5VF6HDiudt56IbB23Ql5/oZ8A7CfZWbgF61sap62XdlOZTZ2rF3c7ltNW1+f7LuDez/uc6uDfO8dwkbPXcKF8vPS9sds527pC2utH0uCb0Jmz2t8wNvN3q2jj4ntDJna94m3g4sb7HH8Gue0RH4Je8z61g4GGr79Wz1qHjbi94m/jcH1IOccsj+lt/sOFr4m0EPz+3XyNueURvSmfn+Ebx1rctMvOxU8foqOwVa+9mfdvHDH+DdYQOxAesvZslvc/wo4vQZy6eY+vdrCVrut/AyTW9CWvO3E1ra4L6i5Fxoka7MDan45vTOmx2MPGc0QH52Tb6kTPxXNGtW5/Tnl+oGP2N/dstY8eeO2M+bqM3zvVxRT+gS8Vdl5/z6CaCzfx/c41o3pP2+030UzrAHDNGv8d4FvMVAf1I4c07V/QlnNsyG9TN23ID/ZjObnO+6CZmydS+y8oG9Dfk2Gd80WcW3Rv44e5bZOLtD8EUHbRq0V0F/DAMn8fQ2UUv2UayEMxplaFvM0G7QR/ufqBcmH/gG85Z9BM8rMO5bdiUDu4ceaLvUjqWfJveQm8hpvnKFv1jOLxUTtkoBWf0nIK5Cd6wO207dAznTlmjH+K630KvuKPbOHYffJsOexykx0iWJ7pNRf+ttEXvW1U49F7ZbJ26RHSe6ehn5NRGMPBVQAfP12EQf8QZPTMxXac30M1RxtaWXLBFn3j0eRsHNIBuCycLtqfWCQZrBcZ0W+gVhXts0RtEXyit4zDOoE/N/5yNzNF3oVB0A93I6ise7bijr1XwbYiurySg7xjfpp+g375mjj5D9HYD3fr6YvkKcxU80Q8duvVt2+gjob/ljX7yFH1a80dvDfpia8GXqp3Wr1XJXevljvFt2QZ6a6tJ2Gvd2Pa8Xuu2iNB7o++r+lUJlQas93oOl04be73Ut7y1Ts4tn/0EfaxZOzcKaXIsqNiI4QtE5x7N7Z08RZ9CKpb38cWs9V26b4sDWURnr3W9foq+gpM8a3S4V+rhKUCcqrBXTufMUxU2QWUTkFtZGls3pjgnqJ4FdB1lZAd8/qMEZGRtAlJvJqONb2syzuj2CuK+1YU5reg2CzGNyqq6fpOpku8VRI7lchX+7SIy8NdQSaKn3K8bsWJOlZGBX2Ed0bUIdBXftJpzG1h2vjetWFqgHXrhczTWtx2h8llXVTytI4FHnaes0bGMqNhC1+jUXmFMx7iCaq6qy4HqxR7dFfMUtc34LQCVDPppcM13Kie5RmTGJYNUKBraDL57xEKalS0UzTgXiiqn1X3fRxR0bBf6TLEvD4aKkslTdO5F4fQUIHseo5ugfrShewbWjvsriHxT65WAByAHVCT7u0fvoKDC+rZClZyf/eSAngUTj1pfCXjshU/8smDiPTr7J374sDPDfI1Hd4cX1g874TmvRc+30U8V9+e88Ig7U6V26Ofk21rzg1ScH3Hj033bTXIZab2iGG6PdWOaQzLx7cShQ0FFfdxqlfFu2DAhxw4vf5zWV3hYZ96m47l7u0+DMAgdu1Dxbs4St+Rx6MbAwzIveLfk8Y2Y9J5HP1tij3DmjZii9lujQy9GXO/M22/5pmvUVdWiV3RkYd50zbfaI7Vb9GmDD0C4t9qLGiy+JPTVKT4A4d5gMY866N4i+p9KuUM767aavpkqLnmDDl10S8W/mSq20O3I3n8x6AXufP4tdKlxcpkZ4HN43FZ0mT3GCmicTO2ysW2uVXmFWp/yb5cdN0kHrb/ADwFN0uPW+ICOt+0SWuPjkW2tPTr+CjcSphjiGIzWodPQGwljMGj4Se/Q0bfJGH4Sj7zx6DJG3tCgo4HQoYiukDHoKB5vZdCtb9MrIUM7DyK169Zu+mEUMtQsjLJrtT7vWl2IGWXnBxjaFwFnraQBhmFs5dDqi66SNLYyGlY6XMgaVip4RG00mHh2LWwwcRhHPVsJG0cdhpDProQNIQ+j52e30kbPa19B5T64H9Wfqn0mTelB7Y04pWMFfCQf5JDTjYOTuSClu5QUSa9EyU0gf5BF7iaP2zxdq6TJjUydgxTD3aPvm5wkSZIkSZIkSZIkSZIkSZIk+Z9kv/534U2+Uyf0XwP9H83PZBlAqkdjAAAAAElFTkSuQmCC';
|
||||||
|
|
||||||
function ArtistBanner(props) {
|
function AuthorBanner(props) {
|
||||||
return (
|
return (
|
||||||
<ArtistImage
|
<AuthorImage
|
||||||
{...props}
|
{...props}
|
||||||
coverType="banner"
|
coverType="banner"
|
||||||
placeholder={bannerPlaceholder}
|
placeholder={bannerPlaceholder}
|
||||||
@@ -14,12 +14,12 @@ function ArtistBanner(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistBanner.propTypes = {
|
AuthorBanner.propTypes = {
|
||||||
size: PropTypes.number.isRequired
|
size: PropTypes.number.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
ArtistBanner.defaultProps = {
|
AuthorBanner.defaultProps = {
|
||||||
size: 70
|
size: 70
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistBanner;
|
export default AuthorBanner;
|
||||||
@@ -17,7 +17,7 @@ function getUrl(image, coverType, size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistImage extends Component {
|
class AuthorImage extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -179,7 +179,7 @@ class ArtistImage extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistImage.propTypes = {
|
AuthorImage.propTypes = {
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
style: PropTypes.object,
|
style: PropTypes.object,
|
||||||
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
@@ -192,10 +192,10 @@ ArtistImage.propTypes = {
|
|||||||
onLoad: PropTypes.func
|
onLoad: PropTypes.func
|
||||||
};
|
};
|
||||||
|
|
||||||
ArtistImage.defaultProps = {
|
AuthorImage.defaultProps = {
|
||||||
size: 250,
|
size: 250,
|
||||||
lazy: true,
|
lazy: true,
|
||||||
overflow: false
|
overflow: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistImage;
|
export default AuthorImage;
|
||||||
@@ -2,19 +2,19 @@ import PropTypes from 'prop-types';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'Components/Link/Link';
|
import Link from 'Components/Link/Link';
|
||||||
|
|
||||||
function ArtistNameLink({ titleSlug, artistName }) {
|
function AuthorNameLink({ titleSlug, authorName }) {
|
||||||
const link = `/author/${titleSlug}`;
|
const link = `/author/${titleSlug}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to={link}>
|
<Link to={link}>
|
||||||
{artistName}
|
{authorName}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistNameLink.propTypes = {
|
AuthorNameLink.propTypes = {
|
||||||
titleSlug: PropTypes.string.isRequired,
|
titleSlug: PropTypes.string.isRequired,
|
||||||
artistName: PropTypes.string.isRequired
|
authorName: PropTypes.string.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistNameLink;
|
export default AuthorNameLink;
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ArtistImage from './ArtistImage';
|
import AuthorImage from './AuthorImage';
|
||||||
|
|
||||||
const posterPlaceholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPcAAAD3AQMAAAD7QlAQAAAABlBMVEUnJychISEIs8G4AAAEFklEQVRYw+2YMdPOQBDH95KQDEVSMKOj1FFQJx9BQc0nkeuUvoLS+AQ6MQqlRu8xCjpUgsjK7iXz2t1LMsbo8i/ey5vfc3e7m7tk9+DQoUOHDpGe3bu7hS8BwJ117BoAOLfOb/Hf62s4EY1VNrcPVvjNua1WuJ/b8xqoeR3sqFkllx8+AYAra9PniDg1ydr07cT7FQMy6k7ycQMKgJr5F4BrhvI9ZA3xCDU8fJggs9gBXJ35acX8lil74CPmO5w1xhwoIMVFMQcqKCfynH3soLLuEfkB4O5TBArDPZlH05ZkYMxBigyJDEyseylHFjjK4CzPyS4IE3gTgIxuAyulHzbG/as0PYsifM24X8/TA19Vxn2efjagNwFoHE2/GDAKpm86HE2AfMrmLQbqADnI2bzFQPv8y7NlM7naORU+uid+62X4xJg0V6PC1+KfvvSghWMgnh0cVIArCO694Ib+qWR4HQ257F9oRxu+L2FpzK3h7D5vPwqA5k1OPOwA4iaAOYWnZM4XPhPYT3eWDXriX4sHROjpskF7cC2eBHfUdVjeDw6/4Uk9oHqEz18DH9se8IvgCdQDBS/oLUxcPcB24mnAv+jfXvCMOdwI9jNXDxiJp9w9DCd4Afgdz96fF5GGk3xSCFBHw+gF4PAz9SQCwE7K5UGculJHGuTdKPun+IYHrafAUPfPKJdP4OhL7ErDuf9jfnXn6Gu6+Kj654EPKQIG7iu5PMLacGPO7Qf0EOMvx3LhhRh/5l+GOsahnPkw4Mw7sXzLedzxV+DvscsMZ8X51W0Olp/+5P7qIPlLPMEWP+3z5G94rXinuen/RWzAbe6g7hVvRX/DO8FdjMPB9+O3yD5fwf1fc72+/jcfN/cHRPZPJva/7q/27z9zlPyVfL9Abrgv/oW/Nvyx5vL9rbl5f78R/I3iTnP7fRH83QjVDpfCb4Kr71uxz1FzkN9nxfX32XKVHyj+BfweV/mJkM5Pdnkpsc6PfK64BynDM8lTiU1+l+LPP2iLUJj8sj5z3uaXgMPZFDY/rQDHs/rLTRxMfkwx4mX4hPLjaza/TgIfI/l1xvl5y/wT5+dSCd8rmXf8W2/qgx5S5rRYvAMlri+Ic2MKME9FCdQT/wJ8Ga1vSnzE+Z3l06REJi7qI1VfOXw0xusrCPVZ+6aP12dFqO/qN6d4fZeF+rB804X6sInXl/lrT1vBFtAu1KcuCfWpi9e33VLfJjZAS33ckvlZpH4uedu2nOcWhleiPr9peLFT32fyfGD7fMGBlf/jfCLZOd8oIrw6q4/o2jogzlc2z2fAW8w2nwvd3eqp0YXxCcdiS1HzRC8fw2ezJjvHVtn2tPbhqnOzTgNp1/kdv6pV7ig4RQOruuDBCax1+94dOHTo0KFDk34DoJynpPus3GIAAAAASUVORK5CYII=';
|
const posterPlaceholder = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPcAAAD3AQMAAAD7QlAQAAAABlBMVEUnJychISEIs8G4AAAEFklEQVRYw+2YMdPOQBDH95KQDEVSMKOj1FFQJx9BQc0nkeuUvoLS+AQ6MQqlRu8xCjpUgsjK7iXz2t1LMsbo8i/ey5vfc3e7m7tk9+DQoUOHDpGe3bu7hS8BwJ117BoAOLfOb/Hf62s4EY1VNrcPVvjNua1WuJ/b8xqoeR3sqFkllx8+AYAra9PniDg1ydr07cT7FQMy6k7ycQMKgJr5F4BrhvI9ZA3xCDU8fJggs9gBXJ35acX8lil74CPmO5w1xhwoIMVFMQcqKCfynH3soLLuEfkB4O5TBArDPZlH05ZkYMxBigyJDEyseylHFjjK4CzPyS4IE3gTgIxuAyulHzbG/as0PYsifM24X8/TA19Vxn2efjagNwFoHE2/GDAKpm86HE2AfMrmLQbqADnI2bzFQPv8y7NlM7naORU+uid+62X4xJg0V6PC1+KfvvSghWMgnh0cVIArCO694Ib+qWR4HQ257F9oRxu+L2FpzK3h7D5vPwqA5k1OPOwA4iaAOYWnZM4XPhPYT3eWDXriX4sHROjpskF7cC2eBHfUdVjeDw6/4Uk9oHqEz18DH9se8IvgCdQDBS/oLUxcPcB24mnAv+jfXvCMOdwI9jNXDxiJp9w9DCd4Afgdz96fF5GGk3xSCFBHw+gF4PAz9SQCwE7K5UGculJHGuTdKPun+IYHrafAUPfPKJdP4OhL7ErDuf9jfnXn6Gu6+Kj654EPKQIG7iu5PMLacGPO7Qf0EOMvx3LhhRh/5l+GOsahnPkw4Mw7sXzLedzxV+DvscsMZ8X51W0Olp/+5P7qIPlLPMEWP+3z5G94rXinuen/RWzAbe6g7hVvRX/DO8FdjMPB9+O3yD5fwf1fc72+/jcfN/cHRPZPJva/7q/27z9zlPyVfL9Abrgv/oW/Nvyx5vL9rbl5f78R/I3iTnP7fRH83QjVDpfCb4Kr71uxz1FzkN9nxfX32XKVHyj+BfweV/mJkM5Pdnkpsc6PfK64BynDM8lTiU1+l+LPP2iLUJj8sj5z3uaXgMPZFDY/rQDHs/rLTRxMfkwx4mX4hPLjaza/TgIfI/l1xvl5y/wT5+dSCd8rmXf8W2/qgx5S5rRYvAMlri+Ic2MKME9FCdQT/wJ8Ga1vSnzE+Z3l06REJi7qI1VfOXw0xusrCPVZ+6aP12dFqO/qN6d4fZeF+rB804X6sInXl/lrT1vBFtAu1KcuCfWpi9e33VLfJjZAS33ckvlZpH4uedu2nOcWhleiPr9peLFT32fyfGD7fMGBlf/jfCLZOd8oIrw6q4/o2jogzlc2z2fAW8w2nwvd3eqp0YXxCcdiS1HzRC8fw2ezJjvHVtn2tPbhqnOzTgNp1/kdv6pV7ig4RQOruuDBCax1+94dOHTo0KFDk34DoJynpPus3GIAAAAASUVORK5CYII=';
|
||||||
|
|
||||||
function ArtistPoster(props) {
|
function AuthorPoster(props) {
|
||||||
return (
|
return (
|
||||||
<ArtistImage
|
<AuthorImage
|
||||||
{...props}
|
{...props}
|
||||||
coverType="poster"
|
coverType="poster"
|
||||||
placeholder={posterPlaceholder}
|
placeholder={posterPlaceholder}
|
||||||
@@ -14,12 +14,12 @@ function ArtistPoster(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistPoster.propTypes = {
|
AuthorPoster.propTypes = {
|
||||||
size: PropTypes.number.isRequired
|
size: PropTypes.number.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
ArtistPoster.defaultProps = {
|
AuthorPoster.defaultProps = {
|
||||||
size: 250
|
size: 250
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistPoster;
|
export default AuthorPoster;
|
||||||
@@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { sizes } from 'Helpers/Props';
|
import { sizes } from 'Helpers/Props';
|
||||||
import Modal from 'Components/Modal/Modal';
|
import Modal from 'Components/Modal/Modal';
|
||||||
import DeleteArtistModalContentConnector from './DeleteArtistModalContentConnector';
|
import DeleteAuthorModalContentConnector from './DeleteAuthorModalContentConnector';
|
||||||
|
|
||||||
function DeleteArtistModal(props) {
|
function DeleteAuthorModal(props) {
|
||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
onModalClose,
|
onModalClose,
|
||||||
@@ -17,7 +17,7 @@ function DeleteArtistModal(props) {
|
|||||||
size={sizes.MEDIUM}
|
size={sizes.MEDIUM}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
>
|
>
|
||||||
<DeleteArtistModalContentConnector
|
<DeleteAuthorModalContentConnector
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -25,9 +25,9 @@ function DeleteArtistModal(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteArtistModal.propTypes = {
|
DeleteAuthorModal.propTypes = {
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DeleteArtistModal;
|
export default DeleteAuthorModal;
|
||||||
@@ -11,9 +11,9 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import ModalBody from 'Components/Modal/ModalBody';
|
import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import styles from './DeleteArtistModalContent.css';
|
import styles from './DeleteAuthorModalContent.css';
|
||||||
|
|
||||||
class DeleteArtistModalContent extends Component {
|
class DeleteAuthorModalContent extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -38,7 +38,7 @@ class DeleteArtistModalContent extends Component {
|
|||||||
this.setState({ addImportListExclusion: value });
|
this.setState({ addImportListExclusion: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeleteArtistConfirmed = () => {
|
onDeleteAuthorConfirmed = () => {
|
||||||
const deleteFiles = this.state.deleteFiles;
|
const deleteFiles = this.state.deleteFiles;
|
||||||
const addImportListExclusion = this.state.addImportListExclusion;
|
const addImportListExclusion = this.state.addImportListExclusion;
|
||||||
|
|
||||||
@@ -52,26 +52,26 @@ class DeleteArtistModalContent extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
artistName,
|
authorName,
|
||||||
path,
|
path,
|
||||||
statistics,
|
statistics,
|
||||||
onModalClose
|
onModalClose
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
trackFileCount,
|
bookFileCount,
|
||||||
sizeOnDisk
|
sizeOnDisk
|
||||||
} = statistics;
|
} = statistics;
|
||||||
|
|
||||||
const deleteFiles = this.state.deleteFiles;
|
const deleteFiles = this.state.deleteFiles;
|
||||||
const addImportListExclusion = this.state.addImportListExclusion;
|
const addImportListExclusion = this.state.addImportListExclusion;
|
||||||
|
|
||||||
let deleteFilesLabel = `Delete ${trackFileCount} Track Files`;
|
let deleteFilesLabel = `Delete ${bookFileCount} Book Files`;
|
||||||
let deleteFilesHelpText = 'Delete the track files and artist folder';
|
let deleteFilesHelpText = 'Delete the book files and author folder';
|
||||||
|
|
||||||
if (trackFileCount === 0) {
|
if (bookFileCount === 0) {
|
||||||
deleteFilesLabel = 'Delete Artist Folder';
|
deleteFilesLabel = 'Delete Author Folder';
|
||||||
deleteFilesHelpText = 'Delete the artist folder and its contents';
|
deleteFilesHelpText = 'Delete the author folder and its contents';
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -79,7 +79,7 @@ class DeleteArtistModalContent extends Component {
|
|||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
>
|
>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
Delete - {artistName}
|
Delete - {authorName}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
@@ -112,7 +112,7 @@ class DeleteArtistModalContent extends Component {
|
|||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="addImportListExclusion"
|
name="addImportListExclusion"
|
||||||
value={addImportListExclusion}
|
value={addImportListExclusion}
|
||||||
helpText="Prevent artist from being added to Readarr by Import lists"
|
helpText="Prevent author from being added to Readarr by Import lists"
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onChange={this.onAddImportListExclusionChange}
|
onChange={this.onAddImportListExclusionChange}
|
||||||
/>
|
/>
|
||||||
@@ -121,11 +121,11 @@ class DeleteArtistModalContent extends Component {
|
|||||||
{
|
{
|
||||||
deleteFiles &&
|
deleteFiles &&
|
||||||
<div className={styles.deleteFilesMessage}>
|
<div className={styles.deleteFilesMessage}>
|
||||||
<div>The artist folder <strong>{path}</strong> and all of its content will be deleted.</div>
|
<div>The author folder <strong>{path}</strong> and all of its content will be deleted.</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
!!trackFileCount &&
|
!!bookFileCount &&
|
||||||
<div>{trackFileCount} track files totaling {formatBytes(sizeOnDisk)}</div>
|
<div>{bookFileCount} book files totaling {formatBytes(sizeOnDisk)}</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@@ -139,7 +139,7 @@ class DeleteArtistModalContent extends Component {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={this.onDeleteArtistConfirmed}
|
onPress={this.onDeleteAuthorConfirmed}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
@@ -149,18 +149,18 @@ class DeleteArtistModalContent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteArtistModalContent.propTypes = {
|
DeleteAuthorModalContent.propTypes = {
|
||||||
artistName: PropTypes.string.isRequired,
|
authorName: PropTypes.string.isRequired,
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
statistics: PropTypes.object.isRequired,
|
statistics: PropTypes.object.isRequired,
|
||||||
onDeletePress: PropTypes.func.isRequired,
|
onDeletePress: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
DeleteArtistModalContent.defaultProps = {
|
DeleteAuthorModalContent.defaultProps = {
|
||||||
statistics: {
|
statistics: {
|
||||||
trackFileCount: 0
|
bookFileCount: 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DeleteArtistModalContent;
|
export default DeleteAuthorModalContent;
|
||||||
@@ -2,30 +2,30 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import { deleteArtist } from 'Store/Actions/artistActions';
|
import { deleteAuthor } from 'Store/Actions/authorActions';
|
||||||
import DeleteArtistModalContent from './DeleteArtistModalContent';
|
import DeleteAuthorModalContent from './DeleteAuthorModalContent';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
(artist) => {
|
(author) => {
|
||||||
return artist;
|
return author;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
deleteArtist
|
deleteAuthor
|
||||||
};
|
};
|
||||||
|
|
||||||
class DeleteArtistModalContentConnector extends Component {
|
class DeleteAuthorModalContentConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onDeletePress = (deleteFiles, addImportListExclusion) => {
|
onDeletePress = (deleteFiles, addImportListExclusion) => {
|
||||||
this.props.deleteArtist({
|
this.props.deleteAuthor({
|
||||||
id: this.props.authorId,
|
id: this.props.authorId,
|
||||||
deleteFiles,
|
deleteFiles,
|
||||||
addImportListExclusion
|
addImportListExclusion
|
||||||
@@ -39,7 +39,7 @@ class DeleteArtistModalContentConnector extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<DeleteArtistModalContent
|
<DeleteAuthorModalContent
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onDeletePress={this.onDeletePress}
|
onDeletePress={this.onDeletePress}
|
||||||
/>
|
/>
|
||||||
@@ -47,10 +47,10 @@ class DeleteArtistModalContentConnector extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteArtistModalContentConnector.propTypes = {
|
DeleteAuthorModalContentConnector.propTypes = {
|
||||||
authorId: PropTypes.number.isRequired,
|
authorId: PropTypes.number.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
deleteArtist: PropTypes.func.isRequired
|
deleteAuthor: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(DeleteArtistModalContentConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(DeleteAuthorModalContentConnector);
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styles from './ArtistAlternateTitles.css';
|
import styles from './AuthorAlternateTitles.css';
|
||||||
|
|
||||||
function ArtistAlternateTitles({ alternateTitles }) {
|
function AuthorAlternateTitles({ alternateTitles }) {
|
||||||
return (
|
return (
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
@@ -21,8 +21,8 @@ function ArtistAlternateTitles({ alternateTitles }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistAlternateTitles.propTypes = {
|
AuthorAlternateTitles.propTypes = {
|
||||||
alternateTitles: PropTypes.arrayOf(PropTypes.string).isRequired
|
alternateTitles: PropTypes.arrayOf(PropTypes.string).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistAlternateTitles;
|
export default AuthorAlternateTitles;
|
||||||
@@ -99,11 +99,11 @@
|
|||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.artistNavigationButtons {
|
.authorNavigationButtons {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.artistNavigationButton {
|
.authorNavigationButton {
|
||||||
composes: button from '~Components/Link/IconButton.css';
|
composes: button from '~Components/Link/IconButton.css';
|
||||||
|
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
|
import { Tab, TabList, TabPanel, Tabs } from 'react-tabs';
|
||||||
import TextTruncate from 'react-text-truncate';
|
import TextTruncate from 'react-text-truncate';
|
||||||
import formatBytes from 'Utilities/Number/formatBytes';
|
import formatBytes from 'Utilities/Number/formatBytes';
|
||||||
import selectAll from 'Utilities/Table/selectAll';
|
import selectAll from 'Utilities/Table/selectAll';
|
||||||
@@ -22,20 +22,20 @@ import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
|||||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||||
import Popover from 'Components/Tooltip/Popover';
|
import Popover from 'Components/Tooltip/Popover';
|
||||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||||
import TrackFileEditorTable from 'TrackFile/Editor/TrackFileEditorTable';
|
import BookFileEditorTable from 'BookFile/Editor/BookFileEditorTable';
|
||||||
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
|
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
|
||||||
import RetagPreviewModalConnector from 'Retag/RetagPreviewModalConnector';
|
import RetagPreviewModalConnector from 'Retag/RetagPreviewModalConnector';
|
||||||
import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfileNameConnector';
|
import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfileNameConnector';
|
||||||
import ArtistPoster from 'Artist/ArtistPoster';
|
import AuthorPoster from 'Author/AuthorPoster';
|
||||||
import EditArtistModalConnector from 'Artist/Edit/EditArtistModalConnector';
|
import EditAuthorModalConnector from 'Author/Edit/EditAuthorModalConnector';
|
||||||
import DeleteArtistModal from 'Artist/Delete/DeleteArtistModal';
|
import DeleteAuthorModal from 'Author/Delete/DeleteAuthorModal';
|
||||||
import ArtistHistoryTable from 'Artist/History/ArtistHistoryTable';
|
import AuthorHistoryTable from 'Author/History/AuthorHistoryTable';
|
||||||
import ArtistAlternateTitles from './ArtistAlternateTitles';
|
import AuthorAlternateTitles from './AuthorAlternateTitles';
|
||||||
import ArtistDetailsSeasonConnector from './ArtistDetailsSeasonConnector';
|
import AuthorDetailsSeasonConnector from './AuthorDetailsSeasonConnector';
|
||||||
import AuthorDetailsSeriesConnector from './AuthorDetailsSeriesConnector';
|
import AuthorDetailsSeriesConnector from './AuthorDetailsSeriesConnector';
|
||||||
import ArtistTagsConnector from './ArtistTagsConnector';
|
import AuthorTagsConnector from './AuthorTagsConnector';
|
||||||
import ArtistDetailsLinks from './ArtistDetailsLinks';
|
import AuthorDetailsLinks from './AuthorDetailsLinks';
|
||||||
import styles from './ArtistDetails.css';
|
import styles from './AuthorDetails.css';
|
||||||
import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable';
|
import InteractiveSearchTable from 'InteractiveSearch/InteractiveSearchTable';
|
||||||
import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveSearchFilterMenuConnector';
|
import InteractiveSearchFilterMenuConnector from 'InteractiveSearch/InteractiveSearchFilterMenuConnector';
|
||||||
import InteractiveImportModal from '../../InteractiveImport/InteractiveImportModal';
|
import InteractiveImportModal from '../../InteractiveImport/InteractiveImportModal';
|
||||||
@@ -60,7 +60,7 @@ function getExpandedState(newState) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistDetails extends Component {
|
class AuthorDetails extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -71,8 +71,8 @@ class ArtistDetails extends Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
isOrganizeModalOpen: false,
|
isOrganizeModalOpen: false,
|
||||||
isRetagModalOpen: false,
|
isRetagModalOpen: false,
|
||||||
isEditArtistModalOpen: false,
|
isEditAuthorModalOpen: false,
|
||||||
isDeleteArtistModalOpen: false,
|
isDeleteAuthorModalOpen: false,
|
||||||
isInteractiveImportModalOpen: false,
|
isInteractiveImportModalOpen: false,
|
||||||
allExpanded: false,
|
allExpanded: false,
|
||||||
allCollapsed: false,
|
allCollapsed: false,
|
||||||
@@ -108,23 +108,23 @@ class ArtistDetails extends Component {
|
|||||||
this.setState({ isInteractiveImportModalOpen: false });
|
this.setState({ isInteractiveImportModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onEditArtistPress = () => {
|
onEditAuthorPress = () => {
|
||||||
this.setState({ isEditArtistModalOpen: true });
|
this.setState({ isEditAuthorModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onEditArtistModalClose = () => {
|
onEditAuthorModalClose = () => {
|
||||||
this.setState({ isEditArtistModalOpen: false });
|
this.setState({ isEditAuthorModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeleteArtistPress = () => {
|
onDeleteAuthorPress = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isEditArtistModalOpen: false,
|
isEditAuthorModalOpen: false,
|
||||||
isDeleteArtistModalOpen: true
|
isDeleteAuthorModalOpen: true
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeleteArtistModalClose = () => {
|
onDeleteAuthorModalClose = () => {
|
||||||
this.setState({ isDeleteArtistModalOpen: false });
|
this.setState({ isDeleteAuthorModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onExpandAllPress = () => {
|
onExpandAllPress = () => {
|
||||||
@@ -156,7 +156,7 @@ class ArtistDetails extends Component {
|
|||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
artistName,
|
authorName,
|
||||||
ratings,
|
ratings,
|
||||||
path,
|
path,
|
||||||
statistics,
|
statistics,
|
||||||
@@ -166,7 +166,7 @@ class ArtistDetails extends Component {
|
|||||||
overview,
|
overview,
|
||||||
links,
|
links,
|
||||||
images,
|
images,
|
||||||
artistType,
|
authorType,
|
||||||
alternateTitles,
|
alternateTitles,
|
||||||
tags,
|
tags,
|
||||||
isSaving,
|
isSaving,
|
||||||
@@ -174,30 +174,30 @@ class ArtistDetails extends Component {
|
|||||||
isSearching,
|
isSearching,
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
albumsError,
|
booksError,
|
||||||
trackFilesError,
|
bookFilesError,
|
||||||
hasAlbums,
|
hasBooks,
|
||||||
hasMonitoredAlbums,
|
hasMonitoredBooks,
|
||||||
hasSeries,
|
hasSeries,
|
||||||
series,
|
series,
|
||||||
hasTrackFiles,
|
hasBookFiles,
|
||||||
previousArtist,
|
previousAuthor,
|
||||||
nextArtist,
|
nextAuthor,
|
||||||
onMonitorTogglePress,
|
onMonitorTogglePress,
|
||||||
onRefreshPress,
|
onRefreshPress,
|
||||||
onSearchPress
|
onSearchPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
trackFileCount,
|
bookFileCount,
|
||||||
sizeOnDisk
|
sizeOnDisk
|
||||||
} = statistics;
|
} = statistics;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isOrganizeModalOpen,
|
isOrganizeModalOpen,
|
||||||
isRetagModalOpen,
|
isRetagModalOpen,
|
||||||
isEditArtistModalOpen,
|
isEditAuthorModalOpen,
|
||||||
isDeleteArtistModalOpen,
|
isDeleteAuthorModalOpen,
|
||||||
isInteractiveImportModalOpen,
|
isInteractiveImportModalOpen,
|
||||||
allExpanded,
|
allExpanded,
|
||||||
allCollapsed,
|
allCollapsed,
|
||||||
@@ -206,14 +206,14 @@ class ArtistDetails extends Component {
|
|||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const continuing = status === 'continuing';
|
const continuing = status === 'continuing';
|
||||||
const endedString = artistType === 'Person' ? 'Deceased' : 'Ended';
|
const endedString = authorType === 'Person' ? 'Deceased' : 'Ended';
|
||||||
|
|
||||||
let trackFilesCountMessage = 'No track files';
|
let bookFilesCountMessage = 'No book files';
|
||||||
|
|
||||||
if (trackFileCount === 1) {
|
if (bookFileCount === 1) {
|
||||||
trackFilesCountMessage = '1 track file';
|
bookFilesCountMessage = '1 book file';
|
||||||
} else if (trackFileCount > 1) {
|
} else if (bookFileCount > 1) {
|
||||||
trackFilesCountMessage = `${trackFileCount} track files`;
|
bookFilesCountMessage = `${bookFileCount} book files`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let expandIcon = icons.EXPAND_INDETERMINATE;
|
let expandIcon = icons.EXPAND_INDETERMINATE;
|
||||||
@@ -225,7 +225,7 @@ class ArtistDetails extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent title={artistName}>
|
<PageContent title={authorName}>
|
||||||
<PageToolbar>
|
<PageToolbar>
|
||||||
<PageToolbarSection>
|
<PageToolbarSection>
|
||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
@@ -240,9 +240,9 @@ class ArtistDetails extends Component {
|
|||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Search Monitored"
|
label="Search Monitored"
|
||||||
iconName={icons.SEARCH}
|
iconName={icons.SEARCH}
|
||||||
isDisabled={!monitored || !hasMonitoredAlbums || !hasAlbums}
|
isDisabled={!monitored || !hasMonitoredBooks || !hasBooks}
|
||||||
isSpinning={isSearching}
|
isSpinning={isSearching}
|
||||||
title={hasMonitoredAlbums ? undefined : 'No monitored albums for this artist'}
|
title={hasMonitoredBooks ? undefined : 'No monitored books for this author'}
|
||||||
onPress={onSearchPress}
|
onPress={onSearchPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -251,14 +251,14 @@ class ArtistDetails extends Component {
|
|||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Preview Rename"
|
label="Preview Rename"
|
||||||
iconName={icons.ORGANIZE}
|
iconName={icons.ORGANIZE}
|
||||||
isDisabled={!hasTrackFiles}
|
isDisabled={!hasBookFiles}
|
||||||
onPress={this.onOrganizePress}
|
onPress={this.onOrganizePress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* <PageToolbarButton */}
|
{/* <PageToolbarButton */}
|
||||||
{/* label="Preview Retag" */}
|
{/* label="Preview Retag" */}
|
||||||
{/* iconName={icons.RETAG} */}
|
{/* iconName={icons.RETAG} */}
|
||||||
{/* isDisabled={!hasTrackFiles} */}
|
{/* isDisabled={!hasBookFiles} */}
|
||||||
{/* onPress={this.onRetagPress} */}
|
{/* onPress={this.onRetagPress} */}
|
||||||
{/* /> */}
|
{/* /> */}
|
||||||
|
|
||||||
@@ -273,13 +273,13 @@ class ArtistDetails extends Component {
|
|||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Edit"
|
label="Edit"
|
||||||
iconName={icons.EDIT}
|
iconName={icons.EDIT}
|
||||||
onPress={this.onEditArtistPress}
|
onPress={this.onEditAuthorPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Delete"
|
label="Delete"
|
||||||
iconName={icons.DELETE}
|
iconName={icons.DELETE}
|
||||||
onPress={this.onDeleteArtistPress}
|
onPress={this.onDeleteAuthorPress}
|
||||||
/>
|
/>
|
||||||
</PageToolbarSection>
|
</PageToolbarSection>
|
||||||
|
|
||||||
@@ -304,7 +304,7 @@ class ArtistDetails extends Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.headerContent}>
|
<div className={styles.headerContent}>
|
||||||
<ArtistPoster
|
<AuthorPoster
|
||||||
className={styles.poster}
|
className={styles.poster}
|
||||||
images={images}
|
images={images}
|
||||||
size={250}
|
size={250}
|
||||||
@@ -325,7 +325,7 @@ class ArtistDetails extends Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.title}>
|
<div className={styles.title}>
|
||||||
{artistName}
|
{authorName}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -339,36 +339,36 @@ class ArtistDetails extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
title="Alternate Titles"
|
title="Alternate Titles"
|
||||||
body={<ArtistAlternateTitles alternateTitles={alternateTitles} />}
|
body={<AuthorAlternateTitles alternateTitles={alternateTitles} />}
|
||||||
position={tooltipPositions.BOTTOM}
|
position={tooltipPositions.BOTTOM}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.artistNavigationButtons}>
|
<div className={styles.authorNavigationButtons}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.artistNavigationButton}
|
className={styles.authorNavigationButton}
|
||||||
name={icons.ARROW_LEFT}
|
name={icons.ARROW_LEFT}
|
||||||
size={30}
|
size={30}
|
||||||
title={`Go to ${previousArtist.artistName}`}
|
title={`Go to ${previousAuthor.authorName}`}
|
||||||
to={`/author/${previousArtist.titleSlug}`}
|
to={`/author/${previousAuthor.titleSlug}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.artistNavigationButton}
|
className={styles.authorNavigationButton}
|
||||||
name={icons.ARROW_UP}
|
name={icons.ARROW_UP}
|
||||||
size={30}
|
size={30}
|
||||||
title={'Go to artist listing'}
|
title={'Go to author listing'}
|
||||||
to={'/'}
|
to={'/'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
className={styles.artistNavigationButton}
|
className={styles.authorNavigationButton}
|
||||||
name={icons.ARROW_RIGHT}
|
name={icons.ARROW_RIGHT}
|
||||||
size={30}
|
size={30}
|
||||||
title={`Go to ${nextArtist.artistName}`}
|
title={`Go to ${nextAuthor.authorName}`}
|
||||||
to={`/author/${nextArtist.titleSlug}`}
|
to={`/author/${nextAuthor.titleSlug}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -399,7 +399,7 @@ class ArtistDetails extends Component {
|
|||||||
|
|
||||||
<Label
|
<Label
|
||||||
className={styles.detailsLabel}
|
className={styles.detailsLabel}
|
||||||
title={trackFilesCountMessage}
|
title={bookFilesCountMessage}
|
||||||
size={sizes.LARGE}
|
size={sizes.LARGE}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
@@ -449,11 +449,11 @@ class ArtistDetails extends Component {
|
|||||||
|
|
||||||
<Label
|
<Label
|
||||||
className={styles.detailsLabel}
|
className={styles.detailsLabel}
|
||||||
title={continuing ? 'More albums are expected' : 'No additional albums are expected'}
|
title={continuing ? 'More books are expected' : 'No additional books are expected'}
|
||||||
size={sizes.LARGE}
|
size={sizes.LARGE}
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
name={continuing ? icons.ARTIST_CONTINUING : icons.ARTIST_ENDED}
|
name={continuing ? icons.AUTHOR_CONTINUING : icons.AUTHOR_ENDED}
|
||||||
size={17}
|
size={17}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -479,7 +479,7 @@ class ArtistDetails extends Component {
|
|||||||
</Label>
|
</Label>
|
||||||
}
|
}
|
||||||
tooltip={
|
tooltip={
|
||||||
<ArtistDetailsLinks
|
<AuthorDetailsLinks
|
||||||
links={links}
|
links={links}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@@ -505,7 +505,7 @@ class ArtistDetails extends Component {
|
|||||||
</span>
|
</span>
|
||||||
</Label>
|
</Label>
|
||||||
}
|
}
|
||||||
tooltip={<ArtistTagsConnector authorId={id} />}
|
tooltip={<AuthorTagsConnector authorId={id} />}
|
||||||
kind={kinds.INVERSE}
|
kind={kinds.INVERSE}
|
||||||
position={tooltipPositions.BOTTOM}
|
position={tooltipPositions.BOTTOM}
|
||||||
/>
|
/>
|
||||||
@@ -524,18 +524,18 @@ class ArtistDetails extends Component {
|
|||||||
|
|
||||||
<div className={styles.contentContainer}>
|
<div className={styles.contentContainer}>
|
||||||
{
|
{
|
||||||
!isPopulated && !albumsError && !trackFilesError &&
|
!isPopulated && !booksError && !bookFilesError &&
|
||||||
<LoadingIndicator />
|
<LoadingIndicator />
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && albumsError &&
|
!isFetching && booksError &&
|
||||||
<div>Loading albums failed</div>
|
<div>Loading books failed</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && trackFilesError &&
|
!isFetching && bookFilesError &&
|
||||||
<div>Loading track files failed</div>
|
<div>Loading book files failed</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -583,14 +583,14 @@ class ArtistDetails extends Component {
|
|||||||
selectedTabIndex === 3 &&
|
selectedTabIndex === 3 &&
|
||||||
<div className={styles.filterIcon}>
|
<div className={styles.filterIcon}>
|
||||||
<InteractiveSearchFilterMenuConnector
|
<InteractiveSearchFilterMenuConnector
|
||||||
type="artist"
|
type="author"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<ArtistDetailsSeasonConnector
|
<AuthorDetailsSeasonConnector
|
||||||
authorId={id}
|
authorId={id}
|
||||||
isExpanded={true}
|
isExpanded={true}
|
||||||
onExpandPress={this.onExpandPress}
|
onExpandPress={this.onExpandPress}
|
||||||
@@ -619,20 +619,20 @@ class ArtistDetails extends Component {
|
|||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<ArtistHistoryTable
|
<AuthorHistoryTable
|
||||||
authorId={id}
|
authorId={id}
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<InteractiveSearchTable
|
<InteractiveSearchTable
|
||||||
type="artist"
|
type="author"
|
||||||
authorId={id}
|
authorId={id}
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<TrackFileEditorTable
|
<BookFileEditorTable
|
||||||
authorId={id}
|
authorId={id}
|
||||||
/>
|
/>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
@@ -645,7 +645,7 @@ class ArtistDetails extends Component {
|
|||||||
Missing or too many books? Modify or create a new
|
Missing or too many books? Modify or create a new
|
||||||
<Link to='/settings/profiles'> Metadata Profile </Link>
|
<Link to='/settings/profiles'> Metadata Profile </Link>
|
||||||
or manually
|
or manually
|
||||||
<Link to={`/add/search?term=${encodeURIComponent(artistName)}`}> Search </Link>
|
<Link to={`/add/search?term=${encodeURIComponent(authorName)}`}> Search </Link>
|
||||||
for new items!
|
for new items!
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -661,23 +661,23 @@ class ArtistDetails extends Component {
|
|||||||
onModalClose={this.onRetagModalClose}
|
onModalClose={this.onRetagModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EditArtistModalConnector
|
<EditAuthorModalConnector
|
||||||
isOpen={isEditArtistModalOpen}
|
isOpen={isEditAuthorModalOpen}
|
||||||
authorId={id}
|
authorId={id}
|
||||||
onModalClose={this.onEditArtistModalClose}
|
onModalClose={this.onEditAuthorModalClose}
|
||||||
onDeleteArtistPress={this.onDeleteArtistPress}
|
onDeleteAuthorPress={this.onDeleteAuthorPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DeleteArtistModal
|
<DeleteAuthorModal
|
||||||
isOpen={isDeleteArtistModalOpen}
|
isOpen={isDeleteAuthorModalOpen}
|
||||||
authorId={id}
|
authorId={id}
|
||||||
onModalClose={this.onDeleteArtistModalClose}
|
onModalClose={this.onDeleteAuthorModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InteractiveImportModal
|
<InteractiveImportModal
|
||||||
isOpen={isInteractiveImportModalOpen}
|
isOpen={isInteractiveImportModalOpen}
|
||||||
folder={path}
|
folder={path}
|
||||||
allowArtistChange={false}
|
allowAuthorChange={false}
|
||||||
showFilterExistingFiles={true}
|
showFilterExistingFiles={true}
|
||||||
showImportMode={false}
|
showImportMode={false}
|
||||||
onModalClose={this.onInteractiveImportModalClose}
|
onModalClose={this.onInteractiveImportModalClose}
|
||||||
@@ -688,15 +688,15 @@ class ArtistDetails extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistDetails.propTypes = {
|
AuthorDetails.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
artistName: PropTypes.string.isRequired,
|
authorName: PropTypes.string.isRequired,
|
||||||
ratings: PropTypes.object.isRequired,
|
ratings: PropTypes.object.isRequired,
|
||||||
path: PropTypes.string.isRequired,
|
path: PropTypes.string.isRequired,
|
||||||
statistics: PropTypes.object.isRequired,
|
statistics: PropTypes.object.isRequired,
|
||||||
qualityProfileId: PropTypes.number.isRequired,
|
qualityProfileId: PropTypes.number.isRequired,
|
||||||
monitored: PropTypes.bool.isRequired,
|
monitored: PropTypes.bool.isRequired,
|
||||||
artistType: PropTypes.string,
|
authorType: PropTypes.string,
|
||||||
status: PropTypes.string.isRequired,
|
status: PropTypes.string.isRequired,
|
||||||
overview: PropTypes.string.isRequired,
|
overview: PropTypes.string.isRequired,
|
||||||
links: PropTypes.arrayOf(PropTypes.object).isRequired,
|
links: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
@@ -708,24 +708,24 @@ ArtistDetails.propTypes = {
|
|||||||
isSearching: PropTypes.bool.isRequired,
|
isSearching: PropTypes.bool.isRequired,
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
albumsError: PropTypes.object,
|
booksError: PropTypes.object,
|
||||||
trackFilesError: PropTypes.object,
|
bookFilesError: PropTypes.object,
|
||||||
hasAlbums: PropTypes.bool.isRequired,
|
hasBooks: PropTypes.bool.isRequired,
|
||||||
hasMonitoredAlbums: PropTypes.bool.isRequired,
|
hasMonitoredBooks: PropTypes.bool.isRequired,
|
||||||
hasSeries: PropTypes.bool.isRequired,
|
hasSeries: PropTypes.bool.isRequired,
|
||||||
series: PropTypes.arrayOf(PropTypes.object).isRequired,
|
series: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
hasTrackFiles: PropTypes.bool.isRequired,
|
hasBookFiles: PropTypes.bool.isRequired,
|
||||||
previousArtist: PropTypes.object.isRequired,
|
previousAuthor: PropTypes.object.isRequired,
|
||||||
nextArtist: PropTypes.object.isRequired,
|
nextAuthor: PropTypes.object.isRequired,
|
||||||
onMonitorTogglePress: PropTypes.func.isRequired,
|
onMonitorTogglePress: PropTypes.func.isRequired,
|
||||||
onRefreshPress: PropTypes.func.isRequired,
|
onRefreshPress: PropTypes.func.isRequired,
|
||||||
onSearchPress: PropTypes.func.isRequired
|
onSearchPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
ArtistDetails.defaultProps = {
|
AuthorDetails.defaultProps = {
|
||||||
statistics: {},
|
statistics: {},
|
||||||
tags: [],
|
tags: [],
|
||||||
isSaving: false
|
isSaving: false
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistDetails;
|
export default AuthorDetails;
|
||||||
@@ -7,37 +7,37 @@ import { createSelector } from 'reselect';
|
|||||||
import { findCommand, isCommandExecuting } from 'Utilities/Command';
|
import { findCommand, isCommandExecuting } from 'Utilities/Command';
|
||||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
||||||
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
|
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
|
||||||
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
|
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
|
||||||
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
||||||
import { fetchAlbums, clearAlbums } from 'Store/Actions/albumActions';
|
import { clearBooks, fetchBooks } from 'Store/Actions/bookActions';
|
||||||
import { fetchSeries, clearSeries } from 'Store/Actions/seriesActions';
|
import { clearSeries, fetchSeries } from 'Store/Actions/seriesActions';
|
||||||
import { fetchTrackFiles, clearTrackFiles } from 'Store/Actions/trackFileActions';
|
import { clearBookFiles, fetchBookFiles } from 'Store/Actions/bookFileActions';
|
||||||
import { toggleArtistMonitored } from 'Store/Actions/artistActions';
|
import { toggleAuthorMonitored } from 'Store/Actions/authorActions';
|
||||||
import { fetchQueueDetails, clearQueueDetails } from 'Store/Actions/queueActions';
|
import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions';
|
||||||
import { clearReleases, cancelFetchReleases } from 'Store/Actions/releaseActions';
|
import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import ArtistDetails from './ArtistDetails';
|
import AuthorDetails from './AuthorDetails';
|
||||||
|
|
||||||
const selectAlbums = createSelector(
|
const selectBooks = createSelector(
|
||||||
(state) => state.albums,
|
(state) => state.books,
|
||||||
(albums) => {
|
(books) => {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error
|
error
|
||||||
} = albums;
|
} = books;
|
||||||
|
|
||||||
const hasAlbums = !!items.length;
|
const hasBooks = !!items.length;
|
||||||
const hasMonitoredAlbums = items.some((e) => e.monitored);
|
const hasMonitoredBooks = items.some((e) => e.monitored);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isAlbumsFetching: isFetching,
|
isBooksFetching: isFetching,
|
||||||
isAlbumsPopulated: isPopulated,
|
isBooksPopulated: isPopulated,
|
||||||
albumsError: error,
|
booksError: error,
|
||||||
hasAlbums,
|
hasBooks,
|
||||||
hasMonitoredAlbums
|
hasMonitoredBooks
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -65,23 +65,23 @@ const selectSeries = createSelector(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectTrackFiles = createSelector(
|
const selectBookFiles = createSelector(
|
||||||
(state) => state.trackFiles,
|
(state) => state.bookFiles,
|
||||||
(trackFiles) => {
|
(bookFiles) => {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error
|
error
|
||||||
} = trackFiles;
|
} = bookFiles;
|
||||||
|
|
||||||
const hasTrackFiles = !!items.length;
|
const hasBookFiles = !!items.length;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isTrackFilesFetching: isFetching,
|
isBookFilesFetching: isFetching,
|
||||||
isTrackFilesPopulated: isPopulated,
|
isBookFilesPopulated: isPopulated,
|
||||||
trackFilesError: error,
|
bookFilesError: error,
|
||||||
hasTrackFiles
|
hasBookFiles
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -89,27 +89,27 @@ const selectTrackFiles = createSelector(
|
|||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { titleSlug }) => titleSlug,
|
(state, { titleSlug }) => titleSlug,
|
||||||
selectAlbums,
|
selectBooks,
|
||||||
selectSeries,
|
selectSeries,
|
||||||
selectTrackFiles,
|
selectBookFiles,
|
||||||
createAllArtistSelector(),
|
createAllAuthorSelector(),
|
||||||
createCommandsSelector(),
|
createCommandsSelector(),
|
||||||
(titleSlug, albums, series, trackFiles, allArtists, commands) => {
|
(titleSlug, books, series, bookFiles, allAuthors, commands) => {
|
||||||
const sortedArtist = _.orderBy(allArtists, 'sortName');
|
const sortedAuthor = _.orderBy(allAuthors, 'sortName');
|
||||||
const artistIndex = _.findIndex(sortedArtist, { titleSlug });
|
const authorIndex = _.findIndex(sortedAuthor, { titleSlug });
|
||||||
const artist = sortedArtist[artistIndex];
|
const author = sortedAuthor[authorIndex];
|
||||||
|
|
||||||
if (!artist) {
|
if (!author) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isAlbumsFetching,
|
isBooksFetching,
|
||||||
isAlbumsPopulated,
|
isBooksPopulated,
|
||||||
albumsError,
|
booksError,
|
||||||
hasAlbums,
|
hasBooks,
|
||||||
hasMonitoredAlbums
|
hasMonitoredBooks
|
||||||
} = albums;
|
} = books;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isSeriesFetching,
|
isSeriesFetching,
|
||||||
@@ -120,34 +120,34 @@ function createMapStateToProps() {
|
|||||||
} = series;
|
} = series;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isTrackFilesFetching,
|
isBookFilesFetching,
|
||||||
isTrackFilesPopulated,
|
isBookFilesPopulated,
|
||||||
trackFilesError,
|
bookFilesError,
|
||||||
hasTrackFiles
|
hasBookFiles
|
||||||
} = trackFiles;
|
} = bookFiles;
|
||||||
|
|
||||||
const previousArtist = sortedArtist[artistIndex - 1] || _.last(sortedArtist);
|
const previousAuthor = sortedAuthor[authorIndex - 1] || _.last(sortedAuthor);
|
||||||
const nextArtist = sortedArtist[artistIndex + 1] || _.first(sortedArtist);
|
const nextAuthor = sortedAuthor[authorIndex + 1] || _.first(sortedAuthor);
|
||||||
const isArtistRefreshing = isCommandExecuting(findCommand(commands, { name: commandNames.REFRESH_ARTIST, authorId: artist.id }));
|
const isAuthorRefreshing = isCommandExecuting(findCommand(commands, { name: commandNames.REFRESH_AUTHOR, authorId: author.id }));
|
||||||
const artistRefreshingCommand = findCommand(commands, { name: commandNames.REFRESH_ARTIST });
|
const authorRefreshingCommand = findCommand(commands, { name: commandNames.REFRESH_AUTHOR });
|
||||||
const allArtistRefreshing = (
|
const allAuthorRefreshing = (
|
||||||
isCommandExecuting(artistRefreshingCommand) &&
|
isCommandExecuting(authorRefreshingCommand) &&
|
||||||
!artistRefreshingCommand.body.authorId
|
!authorRefreshingCommand.body.authorId
|
||||||
);
|
);
|
||||||
const isRefreshing = isArtistRefreshing || allArtistRefreshing;
|
const isRefreshing = isAuthorRefreshing || allAuthorRefreshing;
|
||||||
const isSearching = isCommandExecuting(findCommand(commands, { name: commandNames.ARTIST_SEARCH, authorId: artist.id }));
|
const isSearching = isCommandExecuting(findCommand(commands, { name: commandNames.AUTHOR_SEARCH, authorId: author.id }));
|
||||||
const isRenamingFiles = isCommandExecuting(findCommand(commands, { name: commandNames.RENAME_FILES, authorId: artist.id }));
|
const isRenamingFiles = isCommandExecuting(findCommand(commands, { name: commandNames.RENAME_FILES, authorId: author.id }));
|
||||||
|
|
||||||
const isRenamingArtistCommand = findCommand(commands, { name: commandNames.RENAME_ARTIST });
|
const isRenamingAuthorCommand = findCommand(commands, { name: commandNames.RENAME_AUTHOR });
|
||||||
const isRenamingArtist = (
|
const isRenamingAuthor = (
|
||||||
isCommandExecuting(isRenamingArtistCommand) &&
|
isCommandExecuting(isRenamingAuthorCommand) &&
|
||||||
isRenamingArtistCommand.body.authorIds.indexOf(artist.id) > -1
|
isRenamingAuthorCommand.body.authorIds.indexOf(author.id) > -1
|
||||||
);
|
);
|
||||||
|
|
||||||
const isFetching = isAlbumsFetching || isSeriesFetching || isTrackFilesFetching;
|
const isFetching = isBooksFetching || isSeriesFetching || isBookFilesFetching;
|
||||||
const isPopulated = isAlbumsPopulated && isSeriesPopulated && isTrackFilesPopulated;
|
const isPopulated = isBooksPopulated && isSeriesPopulated && isBookFilesPopulated;
|
||||||
|
|
||||||
const alternateTitles = _.reduce(artist.alternateTitles, (acc, alternateTitle) => {
|
const alternateTitles = _.reduce(author.alternateTitles, (acc, alternateTitle) => {
|
||||||
if ((alternateTitle.seasonNumber === -1 || alternateTitle.seasonNumber === undefined) &&
|
if ((alternateTitle.seasonNumber === -1 || alternateTitle.seasonNumber === undefined) &&
|
||||||
(alternateTitle.sceneSeasonNumber === -1 || alternateTitle.sceneSeasonNumber === undefined)) {
|
(alternateTitle.sceneSeasonNumber === -1 || alternateTitle.sceneSeasonNumber === undefined)) {
|
||||||
acc.push(alternateTitle.title);
|
acc.push(alternateTitle.title);
|
||||||
@@ -157,39 +157,39 @@ function createMapStateToProps() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...artist,
|
...author,
|
||||||
alternateTitles,
|
alternateTitles,
|
||||||
isArtistRefreshing,
|
isAuthorRefreshing,
|
||||||
allArtistRefreshing,
|
allAuthorRefreshing,
|
||||||
isRefreshing,
|
isRefreshing,
|
||||||
isSearching,
|
isSearching,
|
||||||
isRenamingFiles,
|
isRenamingFiles,
|
||||||
isRenamingArtist,
|
isRenamingAuthor,
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
albumsError,
|
booksError,
|
||||||
seriesError,
|
seriesError,
|
||||||
trackFilesError,
|
bookFilesError,
|
||||||
hasAlbums,
|
hasBooks,
|
||||||
hasMonitoredAlbums,
|
hasMonitoredBooks,
|
||||||
hasSeries,
|
hasSeries,
|
||||||
series: seriesItems,
|
series: seriesItems,
|
||||||
hasTrackFiles,
|
hasBookFiles,
|
||||||
previousArtist,
|
previousAuthor,
|
||||||
nextArtist
|
nextAuthor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
fetchAlbums,
|
fetchBooks,
|
||||||
clearAlbums,
|
clearBooks,
|
||||||
fetchSeries,
|
fetchSeries,
|
||||||
clearSeries,
|
clearSeries,
|
||||||
fetchTrackFiles,
|
fetchBookFiles,
|
||||||
clearTrackFiles,
|
clearBookFiles,
|
||||||
toggleArtistMonitored,
|
toggleAuthorMonitored,
|
||||||
fetchQueueDetails,
|
fetchQueueDetails,
|
||||||
clearQueueDetails,
|
clearQueueDetails,
|
||||||
clearReleases,
|
clearReleases,
|
||||||
@@ -197,7 +197,7 @@ const mapDispatchToProps = {
|
|||||||
executeCommand
|
executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArtistDetailsConnector extends Component {
|
class AuthorDetailsConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -210,22 +210,22 @@ class ArtistDetailsConnector extends Component {
|
|||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
isArtistRefreshing,
|
isAuthorRefreshing,
|
||||||
allArtistRefreshing,
|
allAuthorRefreshing,
|
||||||
isRenamingFiles,
|
isRenamingFiles,
|
||||||
isRenamingArtist
|
isRenamingAuthor
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(prevProps.isArtistRefreshing && !isArtistRefreshing) ||
|
(prevProps.isAuthorRefreshing && !isAuthorRefreshing) ||
|
||||||
(prevProps.allArtistRefreshing && !allArtistRefreshing) ||
|
(prevProps.allAuthorRefreshing && !allAuthorRefreshing) ||
|
||||||
(prevProps.isRenamingFiles && !isRenamingFiles) ||
|
(prevProps.isRenamingFiles && !isRenamingFiles) ||
|
||||||
(prevProps.isRenamingArtist && !isRenamingArtist)
|
(prevProps.isRenamingAuthor && !isRenamingAuthor)
|
||||||
) {
|
) {
|
||||||
this.populate();
|
this.populate();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the id has changed we need to clear the albums
|
// If the id has changed we need to clear the books
|
||||||
// files and fetch from the server.
|
// files and fetch from the server.
|
||||||
|
|
||||||
if (prevProps.id !== id) {
|
if (prevProps.id !== id) {
|
||||||
@@ -245,17 +245,17 @@ class ArtistDetailsConnector extends Component {
|
|||||||
populate = () => {
|
populate = () => {
|
||||||
const authorId = this.props.id;
|
const authorId = this.props.id;
|
||||||
|
|
||||||
this.props.fetchAlbums({ authorId });
|
this.props.fetchBooks({ authorId });
|
||||||
this.props.fetchSeries({ authorId });
|
this.props.fetchSeries({ authorId });
|
||||||
this.props.fetchTrackFiles({ authorId });
|
this.props.fetchBookFiles({ authorId });
|
||||||
this.props.fetchQueueDetails({ authorId });
|
this.props.fetchQueueDetails({ authorId });
|
||||||
}
|
}
|
||||||
|
|
||||||
unpopulate = () => {
|
unpopulate = () => {
|
||||||
this.props.cancelFetchReleases();
|
this.props.cancelFetchReleases();
|
||||||
this.props.clearAlbums();
|
this.props.clearBooks();
|
||||||
this.props.clearSeries();
|
this.props.clearSeries();
|
||||||
this.props.clearTrackFiles();
|
this.props.clearBookFiles();
|
||||||
this.props.clearQueueDetails();
|
this.props.clearQueueDetails();
|
||||||
this.props.clearReleases();
|
this.props.clearReleases();
|
||||||
}
|
}
|
||||||
@@ -264,7 +264,7 @@ class ArtistDetailsConnector extends Component {
|
|||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onMonitorTogglePress = (monitored) => {
|
onMonitorTogglePress = (monitored) => {
|
||||||
this.props.toggleArtistMonitored({
|
this.props.toggleAuthorMonitored({
|
||||||
authorId: this.props.id,
|
authorId: this.props.id,
|
||||||
monitored
|
monitored
|
||||||
});
|
});
|
||||||
@@ -272,14 +272,14 @@ class ArtistDetailsConnector extends Component {
|
|||||||
|
|
||||||
onRefreshPress = () => {
|
onRefreshPress = () => {
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.REFRESH_ARTIST,
|
name: commandNames.REFRESH_AUTHOR,
|
||||||
authorId: this.props.id
|
authorId: this.props.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchPress = () => {
|
onSearchPress = () => {
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.ARTIST_SEARCH,
|
name: commandNames.AUTHOR_SEARCH,
|
||||||
authorId: this.props.id
|
authorId: this.props.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,7 @@ class ArtistDetailsConnector extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ArtistDetails
|
<AuthorDetails
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onMonitorTogglePress={this.onMonitorTogglePress}
|
onMonitorTogglePress={this.onMonitorTogglePress}
|
||||||
onRefreshPress={this.onRefreshPress}
|
onRefreshPress={this.onRefreshPress}
|
||||||
@@ -299,21 +299,21 @@ class ArtistDetailsConnector extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistDetailsConnector.propTypes = {
|
AuthorDetailsConnector.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
titleSlug: PropTypes.string.isRequired,
|
titleSlug: PropTypes.string.isRequired,
|
||||||
isArtistRefreshing: PropTypes.bool.isRequired,
|
isAuthorRefreshing: PropTypes.bool.isRequired,
|
||||||
allArtistRefreshing: PropTypes.bool.isRequired,
|
allAuthorRefreshing: PropTypes.bool.isRequired,
|
||||||
isRefreshing: PropTypes.bool.isRequired,
|
isRefreshing: PropTypes.bool.isRequired,
|
||||||
isRenamingFiles: PropTypes.bool.isRequired,
|
isRenamingFiles: PropTypes.bool.isRequired,
|
||||||
isRenamingArtist: PropTypes.bool.isRequired,
|
isRenamingAuthor: PropTypes.bool.isRequired,
|
||||||
fetchAlbums: PropTypes.func.isRequired,
|
fetchBooks: PropTypes.func.isRequired,
|
||||||
clearAlbums: PropTypes.func.isRequired,
|
clearBooks: PropTypes.func.isRequired,
|
||||||
fetchSeries: PropTypes.func.isRequired,
|
fetchSeries: PropTypes.func.isRequired,
|
||||||
clearSeries: PropTypes.func.isRequired,
|
clearSeries: PropTypes.func.isRequired,
|
||||||
fetchTrackFiles: PropTypes.func.isRequired,
|
fetchBookFiles: PropTypes.func.isRequired,
|
||||||
clearTrackFiles: PropTypes.func.isRequired,
|
clearBookFiles: PropTypes.func.isRequired,
|
||||||
toggleArtistMonitored: PropTypes.func.isRequired,
|
toggleAuthorMonitored: PropTypes.func.isRequired,
|
||||||
fetchQueueDetails: PropTypes.func.isRequired,
|
fetchQueueDetails: PropTypes.func.isRequired,
|
||||||
clearQueueDetails: PropTypes.func.isRequired,
|
clearQueueDetails: PropTypes.func.isRequired,
|
||||||
clearReleases: PropTypes.func.isRequired,
|
clearReleases: PropTypes.func.isRequired,
|
||||||
@@ -321,4 +321,4 @@ ArtistDetailsConnector.propTypes = {
|
|||||||
executeCommand: PropTypes.func.isRequired
|
executeCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistDetailsConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorDetailsConnector);
|
||||||
@@ -3,9 +3,9 @@ import React from 'react';
|
|||||||
import { kinds, sizes } from 'Helpers/Props';
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
import Label from 'Components/Label';
|
import Label from 'Components/Label';
|
||||||
import Link from 'Components/Link/Link';
|
import Link from 'Components/Link/Link';
|
||||||
import styles from './ArtistDetailsLinks.css';
|
import styles from './AuthorDetailsLinks.css';
|
||||||
|
|
||||||
function ArtistDetailsLinks(props) {
|
function AuthorDetailsLinks(props) {
|
||||||
const {
|
const {
|
||||||
links
|
links
|
||||||
} = props;
|
} = props;
|
||||||
@@ -41,8 +41,8 @@ function ArtistDetailsLinks(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistDetailsLinks.propTypes = {
|
AuthorDetailsLinks.propTypes = {
|
||||||
links: PropTypes.arrayOf(PropTypes.object).isRequired
|
links: PropTypes.arrayOf(PropTypes.object).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistDetailsLinks;
|
export default AuthorDetailsLinks;
|
||||||
@@ -9,25 +9,25 @@ import PageContent from 'Components/Page/PageContent';
|
|||||||
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
|
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import NotFound from 'Components/NotFound';
|
import NotFound from 'Components/NotFound';
|
||||||
import ArtistDetailsConnector from './ArtistDetailsConnector';
|
import AuthorDetailsConnector from './AuthorDetailsConnector';
|
||||||
import styles from './ArtistDetails.css';
|
import styles from './AuthorDetails.css';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { match }) => match,
|
(state, { match }) => match,
|
||||||
(state) => state.artist,
|
(state) => state.authors,
|
||||||
(match, artist) => {
|
(match, authors) => {
|
||||||
const titleSlug = match.params.titleSlug;
|
const titleSlug = match.params.titleSlug;
|
||||||
const {
|
const {
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
items
|
items
|
||||||
} = artist;
|
} = authors;
|
||||||
|
|
||||||
const artistIndex = _.findIndex(items, { titleSlug });
|
const authorIndex = _.findIndex(items, { titleSlug });
|
||||||
|
|
||||||
if (artistIndex > -1) {
|
if (authorIndex > -1) {
|
||||||
return {
|
return {
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
@@ -48,7 +48,7 @@ const mapDispatchToProps = {
|
|||||||
push
|
push
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArtistDetailsPageConnector extends Component {
|
class AuthorDetailsPageConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -98,14 +98,14 @@ class ArtistDetailsPageConnector extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ArtistDetailsConnector
|
<AuthorDetailsConnector
|
||||||
titleSlug={titleSlug}
|
titleSlug={titleSlug}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistDetailsPageConnector.propTypes = {
|
AuthorDetailsPageConnector.propTypes = {
|
||||||
titleSlug: PropTypes.string,
|
titleSlug: PropTypes.string,
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
@@ -114,4 +114,4 @@ ArtistDetailsPageConnector.propTypes = {
|
|||||||
push: PropTypes.func.isRequired
|
push: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistDetailsPageConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorDetailsPageConnector);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
.albumType {
|
.bookType {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
border: 1px solid $borderColor;
|
border: 1px solid $borderColor;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -18,12 +18,12 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.albumTypeLabel {
|
.bookTypeLabel {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.albumCount {
|
.bookCount {
|
||||||
color: #8895aa;
|
color: #8895aa;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
width: 30px;
|
width: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.albums {
|
.books {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
border-top: 1px solid $borderColor;
|
border-top: 1px solid $borderColor;
|
||||||
}
|
}
|
||||||
@@ -106,13 +106,13 @@
|
|||||||
margin-left: -15px;
|
margin-left: -15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.noAlbums {
|
.noBooks {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointSmall) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.albumType {
|
.bookType {
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
@@ -5,10 +5,10 @@ import getToggledRange from 'Utilities/Table/getToggledRange';
|
|||||||
import { sortDirections } from 'Helpers/Props';
|
import { sortDirections } from 'Helpers/Props';
|
||||||
import Table from 'Components/Table/Table';
|
import Table from 'Components/Table/Table';
|
||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import AlbumRowConnector from './AlbumRowConnector';
|
import BookRowConnector from './BookRowConnector';
|
||||||
import styles from './ArtistDetailsSeason.css';
|
import styles from './AuthorDetailsSeason.css';
|
||||||
|
|
||||||
class ArtistDetailsSeason extends Component {
|
class AuthorDetailsSeason extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -17,15 +17,15 @@ class ArtistDetailsSeason extends Component {
|
|||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
lastToggledAlbum: null
|
lastToggledBook: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onMonitorAlbumPress = (bookId, monitored, { shiftKey }) => {
|
onMonitorBookPress = (bookId, monitored, { shiftKey }) => {
|
||||||
const lastToggled = this.state.lastToggledAlbum;
|
const lastToggled = this.state.lastToggledBook;
|
||||||
const bookIds = [bookId];
|
const bookIds = [bookId];
|
||||||
|
|
||||||
if (shiftKey && lastToggled) {
|
if (shiftKey && lastToggled) {
|
||||||
@@ -37,9 +37,9 @@ class ArtistDetailsSeason extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ lastToggledAlbum: bookId });
|
this.setState({ lastToggledBook: bookId });
|
||||||
|
|
||||||
this.props.onMonitorAlbumPress(_.uniq(bookIds), monitored);
|
this.props.onMonitorBookPress(_.uniq(bookIds), monitored);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -57,9 +57,9 @@ class ArtistDetailsSeason extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.albumType}
|
className={styles.bookType}
|
||||||
>
|
>
|
||||||
<div className={styles.albums}>
|
<div className={styles.books}>
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
sortKey={sortKey}
|
sortKey={sortKey}
|
||||||
@@ -71,11 +71,11 @@ class ArtistDetailsSeason extends Component {
|
|||||||
{
|
{
|
||||||
items.map((item) => {
|
items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<AlbumRowConnector
|
<BookRowConnector
|
||||||
key={item.id}
|
key={item.id}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
{...item}
|
{...item}
|
||||||
onMonitorAlbumPress={this.onMonitorAlbumPress}
|
onMonitorBookPress={this.onMonitorBookPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -88,7 +88,7 @@ class ArtistDetailsSeason extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistDetailsSeason.propTypes = {
|
AuthorDetailsSeason.propTypes = {
|
||||||
sortKey: PropTypes.string,
|
sortKey: PropTypes.string,
|
||||||
sortDirection: PropTypes.oneOf(sortDirections.all),
|
sortDirection: PropTypes.oneOf(sortDirections.all),
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
@@ -96,8 +96,8 @@ ArtistDetailsSeason.propTypes = {
|
|||||||
onTableOptionChange: PropTypes.func.isRequired,
|
onTableOptionChange: PropTypes.func.isRequired,
|
||||||
onExpandPress: PropTypes.func.isRequired,
|
onExpandPress: PropTypes.func.isRequired,
|
||||||
onSortPress: PropTypes.func.isRequired,
|
onSortPress: PropTypes.func.isRequired,
|
||||||
onMonitorAlbumPress: PropTypes.func.isRequired,
|
onMonitorBookPress: PropTypes.func.isRequired,
|
||||||
uiSettings: PropTypes.object.isRequired
|
uiSettings: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistDetailsSeason;
|
export default AuthorDetailsSeason;
|
||||||
@@ -5,40 +5,40 @@ import React, { Component } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
||||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||||
import { toggleAlbumsMonitored, setAlbumsTableOption, setAlbumsSort } from 'Store/Actions/albumActions';
|
import { setBooksSort, setBooksTableOption, toggleBooksMonitored } from 'Store/Actions/bookActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import ArtistDetailsSeason from './ArtistDetailsSeason';
|
import AuthorDetailsSeason from './AuthorDetailsSeason';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { label }) => label,
|
(state, { label }) => label,
|
||||||
createClientSideCollectionSelector('albums'),
|
createClientSideCollectionSelector('books'),
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
createCommandsSelector(),
|
createCommandsSelector(),
|
||||||
createDimensionsSelector(),
|
createDimensionsSelector(),
|
||||||
createUISettingsSelector(),
|
createUISettingsSelector(),
|
||||||
(label, albums, artist, commands, dimensions, uiSettings) => {
|
(label, books, author, commands, dimensions, uiSettings) => {
|
||||||
|
|
||||||
const albumsInGroup = albums.items;
|
const booksInGroup = books.items;
|
||||||
|
|
||||||
let sortDir = 'asc';
|
let sortDir = 'asc';
|
||||||
|
|
||||||
if (albums.sortDirection === 'descending') {
|
if (books.sortDirection === 'descending') {
|
||||||
sortDir = 'desc';
|
sortDir = 'desc';
|
||||||
}
|
}
|
||||||
|
|
||||||
const sortedAlbums = _.orderBy(albumsInGroup, albums.sortKey, sortDir);
|
const sortedBooks = _.orderBy(booksInGroup, books.sortKey, sortDir);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
items: sortedAlbums,
|
items: sortedBooks,
|
||||||
columns: albums.columns,
|
columns: books.columns,
|
||||||
sortKey: albums.sortKey,
|
sortKey: books.sortKey,
|
||||||
sortDirection: albums.sortDirection,
|
sortDirection: books.sortDirection,
|
||||||
artistMonitored: artist.monitored,
|
authorMonitored: author.monitored,
|
||||||
isSmallScreen: dimensions.isSmallScreen,
|
isSmallScreen: dimensions.isSmallScreen,
|
||||||
uiSettings
|
uiSettings
|
||||||
};
|
};
|
||||||
@@ -47,27 +47,27 @@ function createMapStateToProps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
toggleAlbumsMonitored,
|
toggleBooksMonitored,
|
||||||
setAlbumsTableOption,
|
setBooksTableOption,
|
||||||
dispatchSetAlbumSort: setAlbumsSort,
|
dispatchSetBookSort: setBooksSort,
|
||||||
executeCommand
|
executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArtistDetailsSeasonConnector extends Component {
|
class AuthorDetailsSeasonConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onTableOptionChange = (payload) => {
|
onTableOptionChange = (payload) => {
|
||||||
this.props.setAlbumsTableOption(payload);
|
this.props.setBooksTableOption(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSortPress = (sortKey) => {
|
onSortPress = (sortKey) => {
|
||||||
this.props.dispatchSetAlbumSort({ sortKey });
|
this.props.dispatchSetBookSort({ sortKey });
|
||||||
}
|
}
|
||||||
|
|
||||||
onMonitorAlbumPress = (bookIds, monitored) => {
|
onMonitorBookPress = (bookIds, monitored) => {
|
||||||
this.props.toggleAlbumsMonitored({
|
this.props.toggleBooksMonitored({
|
||||||
bookIds,
|
bookIds,
|
||||||
monitored
|
monitored
|
||||||
});
|
});
|
||||||
@@ -78,22 +78,22 @@ class ArtistDetailsSeasonConnector extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ArtistDetailsSeason
|
<AuthorDetailsSeason
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onSortPress={this.onSortPress}
|
onSortPress={this.onSortPress}
|
||||||
onTableOptionChange={this.onTableOptionChange}
|
onTableOptionChange={this.onTableOptionChange}
|
||||||
onMonitorAlbumPress={this.onMonitorAlbumPress}
|
onMonitorBookPress={this.onMonitorBookPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistDetailsSeasonConnector.propTypes = {
|
AuthorDetailsSeasonConnector.propTypes = {
|
||||||
authorId: PropTypes.number.isRequired,
|
authorId: PropTypes.number.isRequired,
|
||||||
toggleAlbumsMonitored: PropTypes.func.isRequired,
|
toggleBooksMonitored: PropTypes.func.isRequired,
|
||||||
setAlbumsTableOption: PropTypes.func.isRequired,
|
setBooksTableOption: PropTypes.func.isRequired,
|
||||||
dispatchSetAlbumSort: PropTypes.func.isRequired,
|
dispatchSetBookSort: PropTypes.func.isRequired,
|
||||||
executeCommand: PropTypes.func.isRequired
|
executeCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistDetailsSeasonConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorDetailsSeasonConnector);
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
.albumType {
|
.bookType {
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
border: 1px solid $borderColor;
|
border: 1px solid $borderColor;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -18,12 +18,12 @@
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.albumTypeLabel {
|
.bookTypeLabel {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.albumCount {
|
.bookCount {
|
||||||
color: #8895aa;
|
color: #8895aa;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
width: 30px;
|
width: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.albums {
|
.books {
|
||||||
padding-top: 15px;
|
padding-top: 15px;
|
||||||
border-top: 1px solid $borderColor;
|
border-top: 1px solid $borderColor;
|
||||||
}
|
}
|
||||||
@@ -108,13 +108,13 @@
|
|||||||
/* margin-left: -15px; */
|
/* margin-left: -15px; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.noAlbums {
|
.noBooks {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointSmall) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
.albumType {
|
.bookType {
|
||||||
border-right: 0;
|
border-right: 0;
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
@@ -8,7 +8,7 @@ import IconButton from 'Components/Link/IconButton';
|
|||||||
import Link from 'Components/Link/Link';
|
import Link from 'Components/Link/Link';
|
||||||
import Table from 'Components/Table/Table';
|
import Table from 'Components/Table/Table';
|
||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import AlbumRowConnector from './AlbumRowConnector';
|
import BookRowConnector from './BookRowConnector';
|
||||||
import styles from './AuthorDetailsSeries.css';
|
import styles from './AuthorDetailsSeries.css';
|
||||||
|
|
||||||
class AuthorDetailsSeries extends Component {
|
class AuthorDetailsSeries extends Component {
|
||||||
@@ -21,8 +21,8 @@ class AuthorDetailsSeries extends Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isOrganizeModalOpen: false,
|
isOrganizeModalOpen: false,
|
||||||
isManageTracksOpen: false,
|
isManageBooksOpen: false,
|
||||||
lastToggledAlbum: null
|
lastToggledBook: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,22 +65,22 @@ class AuthorDetailsSeries extends Component {
|
|||||||
this.props.onExpandPress(id, !isExpanded);
|
this.props.onExpandPress(id, !isExpanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMonitorAlbumPress = (albumId, monitored, { shiftKey }) => {
|
onMonitorBookPress = (bookId, monitored, { shiftKey }) => {
|
||||||
const lastToggled = this.state.lastToggledAlbum;
|
const lastToggled = this.state.lastToggledBook;
|
||||||
const albumIds = [albumId];
|
const bookIds = [bookId];
|
||||||
|
|
||||||
if (shiftKey && lastToggled) {
|
if (shiftKey && lastToggled) {
|
||||||
const { lower, upper } = getToggledRange(this.props.items, albumId, lastToggled);
|
const { lower, upper } = getToggledRange(this.props.items, bookId, lastToggled);
|
||||||
const items = this.props.items;
|
const items = this.props.items;
|
||||||
|
|
||||||
for (let i = lower; i < upper; i++) {
|
for (let i = lower; i < upper; i++) {
|
||||||
albumIds.push(items[i].id);
|
bookIds.push(items[i].id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({ lastToggledAlbum: albumId });
|
this.setState({ lastToggledBook: bookId });
|
||||||
|
|
||||||
this.props.onMonitorAlbumPress(_.uniq(albumIds), monitored);
|
this.props.onMonitorBookPress(_.uniq(bookIds), monitored);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -102,7 +102,7 @@ class AuthorDetailsSeries extends Component {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={styles.albumType}
|
className={styles.bookType}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
className={styles.expandButton}
|
className={styles.expandButton}
|
||||||
@@ -112,11 +112,11 @@ class AuthorDetailsSeries extends Component {
|
|||||||
<div className={styles.left}>
|
<div className={styles.left}>
|
||||||
{
|
{
|
||||||
<div>
|
<div>
|
||||||
<span className={styles.albumTypeLabel}>
|
<span className={styles.bookTypeLabel}>
|
||||||
{label}
|
{label}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span className={styles.albumCount}>
|
<span className={styles.bookCount}>
|
||||||
({items.length} Books)
|
({items.length} Books)
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -142,7 +142,7 @@ class AuthorDetailsSeries extends Component {
|
|||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
isExpanded &&
|
isExpanded &&
|
||||||
<div className={styles.albums}>
|
<div className={styles.books}>
|
||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
sortKey={sortKey}
|
sortKey={sortKey}
|
||||||
@@ -154,12 +154,12 @@ class AuthorDetailsSeries extends Component {
|
|||||||
{
|
{
|
||||||
items.map((item) => {
|
items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<AlbumRowConnector
|
<BookRowConnector
|
||||||
key={item.id}
|
key={item.id}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
{...item}
|
{...item}
|
||||||
position={positionMap[item.id]}
|
position={positionMap[item.id]}
|
||||||
onMonitorAlbumPress={this.onMonitorAlbumPress}
|
onMonitorBookPress={this.onMonitorBookPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -198,7 +198,7 @@ AuthorDetailsSeries.propTypes = {
|
|||||||
onTableOptionChange: PropTypes.func.isRequired,
|
onTableOptionChange: PropTypes.func.isRequired,
|
||||||
onExpandPress: PropTypes.func.isRequired,
|
onExpandPress: PropTypes.func.isRequired,
|
||||||
onSortPress: PropTypes.func.isRequired,
|
onSortPress: PropTypes.func.isRequired,
|
||||||
onMonitorAlbumPress: PropTypes.func.isRequired,
|
onMonitorBookPress: PropTypes.func.isRequired,
|
||||||
uiSettings: PropTypes.object.isRequired
|
uiSettings: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -5,11 +5,11 @@ import React, { Component } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
|
||||||
// import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
// import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||||
import { toggleAlbumsMonitored, setAlbumsTableOption } from 'Store/Actions/albumActions';
|
import { setBooksTableOption, toggleBooksMonitored } from 'Store/Actions/bookActions';
|
||||||
import { setSeriesSort } from 'Store/Actions/seriesActions';
|
import { setSeriesSort } from 'Store/Actions/seriesActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import AuthorDetailsSeries from './AuthorDetailsSeries';
|
import AuthorDetailsSeries from './AuthorDetailsSeries';
|
||||||
@@ -17,8 +17,8 @@ import AuthorDetailsSeries from './AuthorDetailsSeries';
|
|||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { seriesId }) => seriesId,
|
(state, { seriesId }) => seriesId,
|
||||||
(state) => state.albums,
|
(state) => state.books,
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
(state) => state.series,
|
(state) => state.series,
|
||||||
createCommandsSelector(),
|
createCommandsSelector(),
|
||||||
createDimensionsSelector(),
|
createDimensionsSelector(),
|
||||||
@@ -60,7 +60,7 @@ function createMapStateToProps() {
|
|||||||
columns: series.columns,
|
columns: series.columns,
|
||||||
sortKey: series.sortKey,
|
sortKey: series.sortKey,
|
||||||
sortDirection: series.sortDirection,
|
sortDirection: series.sortDirection,
|
||||||
artistMonitored: author.monitored,
|
authorMonitored: author.monitored,
|
||||||
isSmallScreen: dimensions.isSmallScreen,
|
isSmallScreen: dimensions.isSmallScreen,
|
||||||
uiSettings
|
uiSettings
|
||||||
};
|
};
|
||||||
@@ -69,27 +69,27 @@ function createMapStateToProps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
toggleAlbumsMonitored,
|
toggleBooksMonitored,
|
||||||
setAlbumsTableOption,
|
setBooksTableOption,
|
||||||
dispatchSetSeriesSort: setSeriesSort,
|
dispatchSetSeriesSort: setSeriesSort,
|
||||||
executeCommand
|
executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArtistDetailsSeasonConnector extends Component {
|
class AuthorDetailsSeasonConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onTableOptionChange = (payload) => {
|
onTableOptionChange = (payload) => {
|
||||||
this.props.setAlbumsTableOption(payload);
|
this.props.setBooksTableOption(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
onSortPress = (sortKey) => {
|
onSortPress = (sortKey) => {
|
||||||
this.props.dispatchSetSeriesSort({ sortKey });
|
this.props.dispatchSetSeriesSort({ sortKey });
|
||||||
}
|
}
|
||||||
|
|
||||||
onMonitorAlbumPress = (bookIds, monitored) => {
|
onMonitorBookPress = (bookIds, monitored) => {
|
||||||
this.props.toggleAlbumsMonitored({
|
this.props.toggleBooksMonitored({
|
||||||
bookIds,
|
bookIds,
|
||||||
monitored
|
monitored
|
||||||
});
|
});
|
||||||
@@ -104,18 +104,18 @@ class ArtistDetailsSeasonConnector extends Component {
|
|||||||
{...this.props}
|
{...this.props}
|
||||||
onSortPress={this.onSortPress}
|
onSortPress={this.onSortPress}
|
||||||
onTableOptionChange={this.onTableOptionChange}
|
onTableOptionChange={this.onTableOptionChange}
|
||||||
onMonitorAlbumPress={this.onMonitorAlbumPress}
|
onMonitorBookPress={this.onMonitorBookPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistDetailsSeasonConnector.propTypes = {
|
AuthorDetailsSeasonConnector.propTypes = {
|
||||||
authorId: PropTypes.number.isRequired,
|
authorId: PropTypes.number.isRequired,
|
||||||
toggleAlbumsMonitored: PropTypes.func.isRequired,
|
toggleBooksMonitored: PropTypes.func.isRequired,
|
||||||
setAlbumsTableOption: PropTypes.func.isRequired,
|
setBooksTableOption: PropTypes.func.isRequired,
|
||||||
dispatchSetSeriesSort: PropTypes.func.isRequired,
|
dispatchSetSeriesSort: PropTypes.func.isRequired,
|
||||||
executeCommand: PropTypes.func.isRequired
|
executeCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistDetailsSeasonConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorDetailsSeasonConnector);
|
||||||
@@ -3,7 +3,7 @@ import React from 'react';
|
|||||||
import { kinds, sizes } from 'Helpers/Props';
|
import { kinds, sizes } from 'Helpers/Props';
|
||||||
import Label from 'Components/Label';
|
import Label from 'Components/Label';
|
||||||
|
|
||||||
function ArtistTags({ tags }) {
|
function AuthorTags({ tags }) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
@@ -23,8 +23,8 @@ function ArtistTags({ tags }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistTags.propTypes = {
|
AuthorTags.propTypes = {
|
||||||
tags: PropTypes.arrayOf(PropTypes.string).isRequired
|
tags: PropTypes.arrayOf(PropTypes.string).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistTags;
|
export default AuthorTags;
|
||||||
@@ -1,16 +1,16 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
||||||
import ArtistTags from './ArtistTags';
|
import AuthorTags from './AuthorTags';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
createTagsSelector(),
|
createTagsSelector(),
|
||||||
(artist, tagList) => {
|
(author, tagList) => {
|
||||||
const tags = _.reduce(artist.tags, (acc, tag) => {
|
const tags = _.reduce(author.tags, (acc, tag) => {
|
||||||
const matchingTag = _.find(tagList, { id: tag });
|
const matchingTag = _.find(tagList, { id: tag });
|
||||||
|
|
||||||
if (matchingTag) {
|
if (matchingTag) {
|
||||||
@@ -27,4 +27,4 @@ function createMapStateToProps() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(createMapStateToProps)(ArtistTags);
|
export default connect(createMapStateToProps)(AuthorTags);
|
||||||
@@ -6,13 +6,13 @@ import { kinds, sizes } from 'Helpers/Props';
|
|||||||
import TableRow from 'Components/Table/TableRow';
|
import TableRow from 'Components/Table/TableRow';
|
||||||
import Label from 'Components/Label';
|
import Label from 'Components/Label';
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
import AlbumSearchCellConnector from 'Album/AlbumSearchCellConnector';
|
import BookSearchCellConnector from 'Book/BookSearchCellConnector';
|
||||||
import AlbumTitleLink from 'Album/AlbumTitleLink';
|
import BookTitleLink from 'Book/BookTitleLink';
|
||||||
import StarRating from 'Components/StarRating';
|
import StarRating from 'Components/StarRating';
|
||||||
import styles from './AlbumRow.css';
|
import styles from './BookRow.css';
|
||||||
|
|
||||||
function getTrackCountKind(monitored, trackFileCount, trackCount) {
|
function getBookCountKind(monitored, bookFileCount, bookCount) {
|
||||||
if (trackFileCount === trackCount && trackCount > 0) {
|
if (bookFileCount === bookCount && bookCount > 0) {
|
||||||
return kinds.SUCCESS;
|
return kinds.SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ function getTrackCountKind(monitored, trackFileCount, trackCount) {
|
|||||||
return kinds.DANGER;
|
return kinds.DANGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
class AlbumRow extends Component {
|
class BookRow extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -33,7 +33,7 @@ class AlbumRow extends Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isDetailsModalOpen: false,
|
isDetailsModalOpen: false,
|
||||||
isEditAlbumModalOpen: false
|
isEditBookModalOpen: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,16 +48,16 @@ class AlbumRow extends Component {
|
|||||||
this.setState({ isDetailsModalOpen: false });
|
this.setState({ isDetailsModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onEditAlbumPress = () => {
|
onEditBookPress = () => {
|
||||||
this.setState({ isEditAlbumModalOpen: true });
|
this.setState({ isEditBookModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onEditAlbumModalClose = () => {
|
onEditBookModalClose = () => {
|
||||||
this.setState({ isEditAlbumModalOpen: false });
|
this.setState({ isEditBookModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onMonitorAlbumPress = (monitored, options) => {
|
onMonitorBookPress = (monitored, options) => {
|
||||||
this.props.onMonitorAlbumPress(this.props.id, monitored, options);
|
this.props.onMonitorBookPress(this.props.id, monitored, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -75,15 +75,15 @@ class AlbumRow extends Component {
|
|||||||
ratings,
|
ratings,
|
||||||
disambiguation,
|
disambiguation,
|
||||||
isSaving,
|
isSaving,
|
||||||
artistMonitored,
|
authorMonitored,
|
||||||
titleSlug,
|
titleSlug,
|
||||||
columns
|
columns
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
trackCount,
|
bookCount,
|
||||||
trackFileCount,
|
bookFileCount,
|
||||||
totalTrackCount
|
totalBookCount
|
||||||
} = statistics;
|
} = statistics;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -107,9 +107,9 @@ class AlbumRow extends Component {
|
|||||||
>
|
>
|
||||||
<MonitorToggleButton
|
<MonitorToggleButton
|
||||||
monitored={monitored}
|
monitored={monitored}
|
||||||
isDisabled={!artistMonitored}
|
isDisabled={!authorMonitored}
|
||||||
isSaving={isSaving}
|
isSaving={isSaving}
|
||||||
onPress={this.onMonitorAlbumPress}
|
onPress={this.onMonitorBookPress}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
);
|
);
|
||||||
@@ -121,7 +121,7 @@ class AlbumRow extends Component {
|
|||||||
key={name}
|
key={name}
|
||||||
className={styles.title}
|
className={styles.title}
|
||||||
>
|
>
|
||||||
<AlbumTitleLink
|
<BookTitleLink
|
||||||
titleSlug={titleSlug}
|
titleSlug={titleSlug}
|
||||||
title={title}
|
title={title}
|
||||||
disambiguation={disambiguation}
|
disambiguation={disambiguation}
|
||||||
@@ -170,12 +170,12 @@ class AlbumRow extends Component {
|
|||||||
className={styles.status}
|
className={styles.status}
|
||||||
>
|
>
|
||||||
<Label
|
<Label
|
||||||
title={`${totalTrackCount} tracks total. ${trackFileCount} tracks with files.`}
|
title={`${totalBookCount} books total. ${bookFileCount} books with files.`}
|
||||||
kind={getTrackCountKind(monitored, trackFileCount, trackCount)}
|
kind={getBookCountKind(monitored, bookFileCount, bookCount)}
|
||||||
size={sizes.MEDIUM}
|
size={sizes.MEDIUM}
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
<span>{trackFileCount} / {trackCount}</span>
|
<span>{bookFileCount} / {bookCount}</span>
|
||||||
}
|
}
|
||||||
</Label>
|
</Label>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
@@ -184,11 +184,11 @@ class AlbumRow extends Component {
|
|||||||
|
|
||||||
if (name === 'actions') {
|
if (name === 'actions') {
|
||||||
return (
|
return (
|
||||||
<AlbumSearchCellConnector
|
<BookSearchCellConnector
|
||||||
key={name}
|
key={name}
|
||||||
bookId={id}
|
bookId={id}
|
||||||
authorId={authorId}
|
authorId={authorId}
|
||||||
albumTitle={title}
|
bookTitle={title}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -200,7 +200,7 @@ class AlbumRow extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AlbumRow.propTypes = {
|
BookRow.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
authorId: PropTypes.number.isRequired,
|
authorId: PropTypes.number.isRequired,
|
||||||
monitored: PropTypes.bool.isRequired,
|
monitored: PropTypes.bool.isRequired,
|
||||||
@@ -211,17 +211,17 @@ AlbumRow.propTypes = {
|
|||||||
disambiguation: PropTypes.string,
|
disambiguation: PropTypes.string,
|
||||||
titleSlug: PropTypes.string.isRequired,
|
titleSlug: PropTypes.string.isRequired,
|
||||||
isSaving: PropTypes.bool,
|
isSaving: PropTypes.bool,
|
||||||
artistMonitored: PropTypes.bool.isRequired,
|
authorMonitored: PropTypes.bool.isRequired,
|
||||||
statistics: PropTypes.object.isRequired,
|
statistics: PropTypes.object.isRequired,
|
||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
onMonitorAlbumPress: PropTypes.func.isRequired
|
onMonitorBookPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
AlbumRow.defaultProps = {
|
BookRow.defaultProps = {
|
||||||
statistics: {
|
statistics: {
|
||||||
trackCount: 0,
|
bookCount: 0,
|
||||||
trackFileCount: 0
|
bookFileCount: 0
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AlbumRow;
|
export default BookRow;
|
||||||
20
frontend/src/Author/Details/BookRowConnector.js
Normal file
20
frontend/src/Author/Details/BookRowConnector.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/* eslint max-params: 0 */
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { createSelector } from 'reselect';
|
||||||
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
|
import createBookFileSelector from 'Store/Selectors/createBookFileSelector';
|
||||||
|
import BookRow from './BookRow';
|
||||||
|
|
||||||
|
function createMapStateToProps() {
|
||||||
|
return createSelector(
|
||||||
|
createAuthorSelector(),
|
||||||
|
createBookFileSelector(),
|
||||||
|
(author = {}, bookFile) => {
|
||||||
|
return {
|
||||||
|
authorMonitored: author.monitored,
|
||||||
|
bookFilePath: bookFile ? bookFile.path : null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default connect(createMapStateToProps)(BookRow);
|
||||||
@@ -1,15 +1,15 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Modal from 'Components/Modal/Modal';
|
import Modal from 'Components/Modal/Modal';
|
||||||
import EditArtistModalContentConnector from './EditArtistModalContentConnector';
|
import EditAuthorModalContentConnector from './EditAuthorModalContentConnector';
|
||||||
|
|
||||||
function EditArtistModal({ isOpen, onModalClose, ...otherProps }) {
|
function EditAuthorModal({ isOpen, onModalClose, ...otherProps }) {
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
>
|
>
|
||||||
<EditArtistModalContentConnector
|
<EditAuthorModalContentConnector
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -17,9 +17,9 @@ function EditArtistModal({ isOpen, onModalClose, ...otherProps }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditArtistModal.propTypes = {
|
EditAuthorModal.propTypes = {
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EditArtistModal;
|
export default EditAuthorModal;
|
||||||
@@ -2,19 +2,19 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
import { clearPendingChanges } from 'Store/Actions/baseActions';
|
||||||
import EditArtistModal from './EditArtistModal';
|
import EditAuthorModal from './EditAuthorModal';
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
clearPendingChanges
|
clearPendingChanges
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditArtistModalConnector extends Component {
|
class EditAuthorModalConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onModalClose = () => {
|
onModalClose = () => {
|
||||||
this.props.clearPendingChanges({ section: 'artist' });
|
this.props.clearPendingChanges({ section: 'author' });
|
||||||
this.props.onModalClose();
|
this.props.onModalClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ class EditArtistModalConnector extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<EditArtistModal
|
<EditAuthorModal
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onModalClose={this.onModalClose}
|
onModalClose={this.onModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -31,9 +31,9 @@ class EditArtistModalConnector extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EditArtistModalConnector.propTypes = {
|
EditAuthorModalConnector.propTypes = {
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
clearPendingChanges: PropTypes.func.isRequired
|
clearPendingChanges: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(undefined, mapDispatchToProps)(EditArtistModalConnector);
|
export default connect(undefined, mapDispatchToProps)(EditAuthorModalConnector);
|
||||||
@@ -13,11 +13,11 @@ import FormLabel from 'Components/Form/FormLabel';
|
|||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
import Icon from 'Components/Icon';
|
import Icon from 'Components/Icon';
|
||||||
import Popover from 'Components/Tooltip/Popover';
|
import Popover from 'Components/Tooltip/Popover';
|
||||||
import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal';
|
import MoveAuthorModal from 'Author/MoveAuthor/MoveAuthorModal';
|
||||||
import ArtistMetadataProfilePopoverContent from 'AddArtist/ArtistMetadataProfilePopoverContent';
|
import AuthorMetadataProfilePopoverContent from 'AddAuthor/AuthorMetadataProfilePopoverContent';
|
||||||
import styles from './EditArtistModalContent.css';
|
import styles from './EditAuthorModalContent.css';
|
||||||
|
|
||||||
class EditArtistModalContent extends Component {
|
class EditAuthorModalContent extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -48,7 +48,7 @@ class EditArtistModalContent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoveArtistPress = () => {
|
onMoveAuthorPress = () => {
|
||||||
this.setState({ isConfirmMoveModalOpen: false });
|
this.setState({ isConfirmMoveModalOpen: false });
|
||||||
|
|
||||||
this.props.onSavePress(true);
|
this.props.onSavePress(true);
|
||||||
@@ -59,14 +59,14 @@ class EditArtistModalContent extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
artistName,
|
authorName,
|
||||||
item,
|
item,
|
||||||
isSaving,
|
isSaving,
|
||||||
showMetadataProfile,
|
showMetadataProfile,
|
||||||
originalPath,
|
originalPath,
|
||||||
onInputChange,
|
onInputChange,
|
||||||
onModalClose,
|
onModalClose,
|
||||||
onDeleteArtistPress,
|
onDeleteAuthorPress,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ class EditArtistModalContent extends Component {
|
|||||||
return (
|
return (
|
||||||
<ModalContent onModalClose={onModalClose}>
|
<ModalContent onModalClose={onModalClose}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
Edit - {artistName}
|
Edit - {authorName}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
@@ -92,7 +92,7 @@ class EditArtistModalContent extends Component {
|
|||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="monitored"
|
name="monitored"
|
||||||
helpText="Download monitored albums from this artist"
|
helpText="Download monitored books from this author"
|
||||||
{...monitored}
|
{...monitored}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
/>
|
/>
|
||||||
@@ -123,7 +123,7 @@ class EditArtistModalContent extends Component {
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
title="Metadata Profile"
|
title="Metadata Profile"
|
||||||
body={<ArtistMetadataProfilePopoverContent />}
|
body={<AuthorMetadataProfilePopoverContent />}
|
||||||
position={tooltipPositions.RIGHT}
|
position={tooltipPositions.RIGHT}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -132,7 +132,7 @@ class EditArtistModalContent extends Component {
|
|||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.METADATA_PROFILE_SELECT}
|
type={inputTypes.METADATA_PROFILE_SELECT}
|
||||||
name="metadataProfileId"
|
name="metadataProfileId"
|
||||||
helpText="Changes will take place on next artist refresh"
|
helpText="Changes will take place on next author refresh"
|
||||||
includeNone={true}
|
includeNone={true}
|
||||||
{...metadataProfileId}
|
{...metadataProfileId}
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
@@ -167,7 +167,7 @@ class EditArtistModalContent extends Component {
|
|||||||
<Button
|
<Button
|
||||||
className={styles.deleteButton}
|
className={styles.deleteButton}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={onDeleteArtistPress}
|
onPress={onDeleteAuthorPress}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
@@ -186,12 +186,12 @@ class EditArtistModalContent extends Component {
|
|||||||
</SpinnerButton>
|
</SpinnerButton>
|
||||||
</ModalFooter>
|
</ModalFooter>
|
||||||
|
|
||||||
<MoveArtistModal
|
<MoveAuthorModal
|
||||||
originalPath={originalPath}
|
originalPath={originalPath}
|
||||||
destinationPath={path.value}
|
destinationPath={path.value}
|
||||||
isOpen={this.state.isConfirmMoveModalOpen}
|
isOpen={this.state.isConfirmMoveModalOpen}
|
||||||
onSavePress={this.onSavePress}
|
onSavePress={this.onSavePress}
|
||||||
onMoveArtistPress={this.onMoveArtistPress}
|
onMoveAuthorPress={this.onMoveAuthorPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
@@ -199,9 +199,9 @@ class EditArtistModalContent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EditArtistModalContent.propTypes = {
|
EditAuthorModalContent.propTypes = {
|
||||||
authorId: PropTypes.number.isRequired,
|
authorId: PropTypes.number.isRequired,
|
||||||
artistName: PropTypes.string.isRequired,
|
authorName: PropTypes.string.isRequired,
|
||||||
item: PropTypes.object.isRequired,
|
item: PropTypes.object.isRequired,
|
||||||
isSaving: PropTypes.bool.isRequired,
|
isSaving: PropTypes.bool.isRequired,
|
||||||
showMetadataProfile: PropTypes.bool.isRequired,
|
showMetadataProfile: PropTypes.bool.isRequired,
|
||||||
@@ -210,7 +210,7 @@ EditArtistModalContent.propTypes = {
|
|||||||
onInputChange: PropTypes.func.isRequired,
|
onInputChange: PropTypes.func.isRequired,
|
||||||
onSavePress: PropTypes.func.isRequired,
|
onSavePress: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
onDeleteArtistPress: PropTypes.func.isRequired
|
onDeleteAuthorPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default EditArtistModalContent;
|
export default EditAuthorModalContent;
|
||||||
@@ -4,56 +4,55 @@ import React, { Component } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import selectSettings from 'Store/Selectors/selectSettings';
|
import selectSettings from 'Store/Selectors/selectSettings';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import { setArtistValue, saveArtist } from 'Store/Actions/artistActions';
|
import { saveAuthor, setAuthorValue } from 'Store/Actions/authorActions';
|
||||||
import EditArtistModalContent from './EditArtistModalContent';
|
import EditAuthorModalContent from './EditAuthorModalContent';
|
||||||
|
|
||||||
function createIsPathChangingSelector() {
|
function createIsPathChangingSelector() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.artist.pendingChanges,
|
(state) => state.authors.pendingChanges,
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
(pendingChanges, artist) => {
|
(pendingChanges, author) => {
|
||||||
const path = pendingChanges.path;
|
const path = pendingChanges.path;
|
||||||
|
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return artist.path !== path;
|
return author.path !== path;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.artist,
|
(state) => state.authors,
|
||||||
(state) => state.settings.metadataProfiles,
|
(state) => state.settings.metadataProfiles,
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
createIsPathChangingSelector(),
|
createIsPathChangingSelector(),
|
||||||
(artistState, metadataProfiles, artist, isPathChanging) => {
|
(authorsState, metadataProfiles, author, isPathChanging) => {
|
||||||
const {
|
const {
|
||||||
isSaving,
|
isSaving,
|
||||||
saveError,
|
saveError,
|
||||||
pendingChanges
|
pendingChanges
|
||||||
} = artistState;
|
} = authorsState;
|
||||||
|
|
||||||
const artistSettings = _.pick(artist, [
|
const authorSettings = _.pick(author, [
|
||||||
'monitored',
|
'monitored',
|
||||||
'albumFolder',
|
|
||||||
'qualityProfileId',
|
'qualityProfileId',
|
||||||
'metadataProfileId',
|
'metadataProfileId',
|
||||||
'path',
|
'path',
|
||||||
'tags'
|
'tags'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const settings = selectSettings(artistSettings, pendingChanges, saveError);
|
const settings = selectSettings(authorSettings, pendingChanges, saveError);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
artistName: artist.artistName,
|
authorName: author.authorName,
|
||||||
isSaving,
|
isSaving,
|
||||||
saveError,
|
saveError,
|
||||||
isPathChanging,
|
isPathChanging,
|
||||||
originalPath: artist.path,
|
originalPath: author.path,
|
||||||
item: settings.settings,
|
item: settings.settings,
|
||||||
showMetadataProfile: metadataProfiles.items.length > 1,
|
showMetadataProfile: metadataProfiles.items.length > 1,
|
||||||
...settings
|
...settings
|
||||||
@@ -63,11 +62,11 @@ function createMapStateToProps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
dispatchSetArtistValue: setArtistValue,
|
dispatchSetAuthorValue: setAuthorValue,
|
||||||
dispatchSaveArtist: saveArtist
|
dispatchSaveAuthor: saveAuthor
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditArtistModalContentConnector extends Component {
|
class EditAuthorModalContentConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -82,11 +81,11 @@ class EditArtistModalContentConnector extends Component {
|
|||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onInputChange = ({ name, value }) => {
|
onInputChange = ({ name, value }) => {
|
||||||
this.props.dispatchSetArtistValue({ name, value });
|
this.props.dispatchSetAuthorValue({ name, value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onSavePress = (moveFiles) => {
|
onSavePress = (moveFiles) => {
|
||||||
this.props.dispatchSaveArtist({
|
this.props.dispatchSaveAuthor({
|
||||||
id: this.props.authorId,
|
id: this.props.authorId,
|
||||||
moveFiles
|
moveFiles
|
||||||
});
|
});
|
||||||
@@ -97,23 +96,23 @@ class EditArtistModalContentConnector extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<EditArtistModalContent
|
<EditAuthorModalContent
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onInputChange={this.onInputChange}
|
onInputChange={this.onInputChange}
|
||||||
onSavePress={this.onSavePress}
|
onSavePress={this.onSavePress}
|
||||||
onMoveArtistPress={this.onMoveArtistPress}
|
onMoveAuthorPress={this.onMoveAuthorPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EditArtistModalContentConnector.propTypes = {
|
EditAuthorModalContentConnector.propTypes = {
|
||||||
authorId: PropTypes.number,
|
authorId: PropTypes.number,
|
||||||
isSaving: PropTypes.bool.isRequired,
|
isSaving: PropTypes.bool.isRequired,
|
||||||
saveError: PropTypes.object,
|
saveError: PropTypes.object,
|
||||||
dispatchSetArtistValue: PropTypes.func.isRequired,
|
dispatchSetAuthorValue: PropTypes.func.isRequired,
|
||||||
dispatchSaveArtist: PropTypes.func.isRequired,
|
dispatchSaveAuthor: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(EditArtistModalContentConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(EditAuthorModalContentConnector);
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Modal from 'Components/Modal/Modal';
|
import Modal from 'Components/Modal/Modal';
|
||||||
import RetagArtistModalContentConnector from './RetagArtistModalContentConnector';
|
import RetagAuthorModalContentConnector from './RetagAuthorModalContentConnector';
|
||||||
|
|
||||||
function RetagArtistModal(props) {
|
function RetagAuthorModal(props) {
|
||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
onModalClose,
|
onModalClose,
|
||||||
@@ -15,7 +15,7 @@ function RetagArtistModal(props) {
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
>
|
>
|
||||||
<RetagArtistModalContentConnector
|
<RetagAuthorModalContentConnector
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -23,9 +23,9 @@ function RetagArtistModal(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
RetagArtistModal.propTypes = {
|
RetagAuthorModal.propTypes = {
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RetagArtistModal;
|
export default RetagAuthorModal;
|
||||||
@@ -8,24 +8,24 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import ModalBody from 'Components/Modal/ModalBody';
|
import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import styles from './RetagArtistModalContent.css';
|
import styles from './RetagAuthorModalContent.css';
|
||||||
|
|
||||||
function RetagArtistModalContent(props) {
|
function RetagAuthorModalContent(props) {
|
||||||
const {
|
const {
|
||||||
artistNames,
|
authorNames,
|
||||||
onModalClose,
|
onModalClose,
|
||||||
onRetagArtistPress
|
onRetagAuthorPress
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalContent onModalClose={onModalClose}>
|
<ModalContent onModalClose={onModalClose}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
Retag Selected Artist
|
Retag Selected Author
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Alert>
|
<Alert>
|
||||||
Tip: To preview the tags that will be written... select "Cancel" then click any artist name and use the
|
Tip: To preview the tags that will be written... select "Cancel" then click any author name and use the
|
||||||
<Icon
|
<Icon
|
||||||
className={styles.retagIcon}
|
className={styles.retagIcon}
|
||||||
name={icons.RETAG}
|
name={icons.RETAG}
|
||||||
@@ -33,14 +33,14 @@ function RetagArtistModalContent(props) {
|
|||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
<div className={styles.message}>
|
<div className={styles.message}>
|
||||||
Are you sure you want to re-tag all files in the {artistNames.length} selected artist?
|
Are you sure you want to re-tag all files in the {authorNames.length} selected author?
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
artistNames.map((artistName) => {
|
authorNames.map((authorName) => {
|
||||||
return (
|
return (
|
||||||
<li key={artistName}>
|
<li key={authorName}>
|
||||||
{artistName}
|
{authorName}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -55,7 +55,7 @@ function RetagArtistModalContent(props) {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={onRetagArtistPress}
|
onPress={onRetagAuthorPress}
|
||||||
>
|
>
|
||||||
Retag
|
Retag
|
||||||
</Button>
|
</Button>
|
||||||
@@ -64,10 +64,10 @@ function RetagArtistModalContent(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
RetagArtistModalContent.propTypes = {
|
RetagAuthorModalContent.propTypes = {
|
||||||
artistNames: PropTypes.arrayOf(PropTypes.string).isRequired,
|
authorNames: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
onRetagArtistPress: PropTypes.func.isRequired
|
onRetagAuthorPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default RetagArtistModalContent;
|
export default RetagAuthorModalContent;
|
||||||
@@ -3,25 +3,25 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
|
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import RetagArtistModalContent from './RetagArtistModalContent';
|
import RetagAuthorModalContent from './RetagAuthorModalContent';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { authorIds }) => authorIds,
|
(state, { authorIds }) => authorIds,
|
||||||
createAllArtistSelector(),
|
createAllAuthorSelector(),
|
||||||
(authorIds, allArtists) => {
|
(authorIds, allAuthors) => {
|
||||||
const artist = _.intersectionWith(allArtists, authorIds, (s, id) => {
|
const author = _.intersectionWith(allAuthors, authorIds, (s, id) => {
|
||||||
return s.id === id;
|
return s.id === id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const sortedArtist = _.orderBy(artist, 'sortName');
|
const sortedAuthor = _.orderBy(author, 'sortName');
|
||||||
const artistNames = _.map(sortedArtist, 'artistName');
|
const authorNames = _.map(sortedAuthor, 'authorName');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
artistNames
|
authorNames
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -31,14 +31,14 @@ const mapDispatchToProps = {
|
|||||||
executeCommand
|
executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class RetagArtistModalContentConnector extends Component {
|
class RetagAuthorModalContentConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onRetagArtistPress = () => {
|
onRetagAuthorPress = () => {
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.RETAG_ARTIST,
|
name: commandNames.RETAG_AUTHOR,
|
||||||
authorIds: this.props.authorIds
|
authorIds: this.props.authorIds
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -50,18 +50,18 @@ class RetagArtistModalContentConnector extends Component {
|
|||||||
|
|
||||||
render(props) {
|
render(props) {
|
||||||
return (
|
return (
|
||||||
<RetagArtistModalContent
|
<RetagAuthorModalContent
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onRetagArtistPress={this.onRetagArtistPress}
|
onRetagAuthorPress={this.onRetagAuthorPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RetagArtistModalContentConnector.propTypes = {
|
RetagAuthorModalContentConnector.propTypes = {
|
||||||
authorIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
authorIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
executeCommand: PropTypes.func.isRequired
|
executeCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(RetagArtistModalContentConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(RetagAuthorModalContentConnector);
|
||||||
@@ -13,12 +13,12 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
|||||||
import FilterMenu from 'Components/Menu/FilterMenu';
|
import FilterMenu from 'Components/Menu/FilterMenu';
|
||||||
import Table from 'Components/Table/Table';
|
import Table from 'Components/Table/Table';
|
||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import NoArtist from 'Artist/NoArtist';
|
import NoAuthor from 'Author/NoAuthor';
|
||||||
import OrganizeArtistModal from './Organize/OrganizeArtistModal';
|
import OrganizeAuthorModal from './Organize/OrganizeAuthorModal';
|
||||||
import RetagArtistModal from './AudioTags/RetagArtistModal';
|
import RetagAuthorModal from './AudioTags/RetagAuthorModal';
|
||||||
import ArtistEditorRowConnector from './ArtistEditorRowConnector';
|
import AuthorEditorRowConnector from './AuthorEditorRowConnector';
|
||||||
import ArtistEditorFooter from './ArtistEditorFooter';
|
import AuthorEditorFooter from './AuthorEditorFooter';
|
||||||
import ArtistEditorFilterModalConnector from './ArtistEditorFilterModalConnector';
|
import AuthorEditorFilterModalConnector from './AuthorEditorFilterModalConnector';
|
||||||
|
|
||||||
function getColumns(showMetadataProfile) {
|
function getColumns(showMetadataProfile) {
|
||||||
return [
|
return [
|
||||||
@@ -60,7 +60,7 @@ function getColumns(showMetadataProfile) {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistEditor extends Component {
|
class AuthorEditor extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -73,8 +73,8 @@ class ArtistEditor extends Component {
|
|||||||
allUnselected: false,
|
allUnselected: false,
|
||||||
lastToggled: null,
|
lastToggled: null,
|
||||||
selectedState: {},
|
selectedState: {},
|
||||||
isOrganizingArtistModalOpen: false,
|
isOrganizingAuthorModalOpen: false,
|
||||||
isRetaggingArtistModalOpen: false,
|
isRetaggingAuthorModalOpen: false,
|
||||||
columns: getColumns(props.showMetadataProfile)
|
columns: getColumns(props.showMetadataProfile)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -121,24 +121,24 @@ class ArtistEditor extends Component {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onOrganizeArtistPress = () => {
|
onOrganizeAuthorPress = () => {
|
||||||
this.setState({ isOrganizingArtistModalOpen: true });
|
this.setState({ isOrganizingAuthorModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onOrganizeArtistModalClose = (organized) => {
|
onOrganizeAuthorModalClose = (organized) => {
|
||||||
this.setState({ isOrganizingArtistModalOpen: false });
|
this.setState({ isOrganizingAuthorModalOpen: false });
|
||||||
|
|
||||||
if (organized === true) {
|
if (organized === true) {
|
||||||
this.onSelectAllChange({ value: false });
|
this.onSelectAllChange({ value: false });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRetagArtistPress = () => {
|
onRetagAuthorPress = () => {
|
||||||
this.setState({ isRetaggingArtistModalOpen: true });
|
this.setState({ isRetaggingAuthorModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onRetagArtistModalClose = (organized) => {
|
onRetagAuthorModalClose = (organized) => {
|
||||||
this.setState({ isRetaggingArtistModalOpen: false });
|
this.setState({ isRetaggingAuthorModalOpen: false });
|
||||||
|
|
||||||
if (organized === true) {
|
if (organized === true) {
|
||||||
this.onSelectAllChange({ value: false });
|
this.onSelectAllChange({ value: false });
|
||||||
@@ -164,8 +164,8 @@ class ArtistEditor extends Component {
|
|||||||
saveError,
|
saveError,
|
||||||
isDeleting,
|
isDeleting,
|
||||||
deleteError,
|
deleteError,
|
||||||
isOrganizingArtist,
|
isOrganizingAuthor,
|
||||||
isRetaggingArtist,
|
isRetaggingAuthor,
|
||||||
showMetadataProfile,
|
showMetadataProfile,
|
||||||
onSortPress,
|
onSortPress,
|
||||||
onFilterSelect
|
onFilterSelect
|
||||||
@@ -181,7 +181,7 @@ class ArtistEditor extends Component {
|
|||||||
const selectedAuthorIds = this.getSelectedIds();
|
const selectedAuthorIds = this.getSelectedIds();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent title="Artist Editor">
|
<PageContent title="Author Editor">
|
||||||
<PageToolbar>
|
<PageToolbar>
|
||||||
<PageToolbarSection />
|
<PageToolbarSection />
|
||||||
<PageToolbarSection alignContent={align.RIGHT}>
|
<PageToolbarSection alignContent={align.RIGHT}>
|
||||||
@@ -190,7 +190,7 @@ class ArtistEditor extends Component {
|
|||||||
selectedFilterKey={selectedFilterKey}
|
selectedFilterKey={selectedFilterKey}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
customFilters={customFilters}
|
customFilters={customFilters}
|
||||||
filterModalConnectorComponent={ArtistEditorFilterModalConnector}
|
filterModalConnectorComponent={AuthorEditorFilterModalConnector}
|
||||||
onFilterSelect={onFilterSelect}
|
onFilterSelect={onFilterSelect}
|
||||||
/>
|
/>
|
||||||
</PageToolbarSection>
|
</PageToolbarSection>
|
||||||
@@ -204,7 +204,7 @@ class ArtistEditor extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>{getErrorMessage(error, 'Failed to load artist from API')}</div>
|
<div>{getErrorMessage(error, 'Failed to load author from API')}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -224,7 +224,7 @@ class ArtistEditor extends Component {
|
|||||||
{
|
{
|
||||||
items.map((item) => {
|
items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<ArtistEditorRowConnector
|
<AuthorEditorRowConnector
|
||||||
key={item.id}
|
key={item.id}
|
||||||
{...item}
|
{...item}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
@@ -241,35 +241,35 @@ class ArtistEditor extends Component {
|
|||||||
|
|
||||||
{
|
{
|
||||||
!error && isPopulated && !items.length &&
|
!error && isPopulated && !items.length &&
|
||||||
<NoArtist totalItems={totalItems} />
|
<NoAuthor totalItems={totalItems} />
|
||||||
}
|
}
|
||||||
</PageContentBodyConnector>
|
</PageContentBodyConnector>
|
||||||
|
|
||||||
<ArtistEditorFooter
|
<AuthorEditorFooter
|
||||||
authorIds={selectedAuthorIds}
|
authorIds={selectedAuthorIds}
|
||||||
selectedCount={selectedAuthorIds.length}
|
selectedCount={selectedAuthorIds.length}
|
||||||
isSaving={isSaving}
|
isSaving={isSaving}
|
||||||
saveError={saveError}
|
saveError={saveError}
|
||||||
isDeleting={isDeleting}
|
isDeleting={isDeleting}
|
||||||
deleteError={deleteError}
|
deleteError={deleteError}
|
||||||
isOrganizingArtist={isOrganizingArtist}
|
isOrganizingAuthor={isOrganizingAuthor}
|
||||||
isRetaggingArtist={isRetaggingArtist}
|
isRetaggingAuthor={isRetaggingAuthor}
|
||||||
showMetadataProfile={showMetadataProfile}
|
showMetadataProfile={showMetadataProfile}
|
||||||
onSaveSelected={this.onSaveSelected}
|
onSaveSelected={this.onSaveSelected}
|
||||||
onOrganizeArtistPress={this.onOrganizeArtistPress}
|
onOrganizeAuthorPress={this.onOrganizeAuthorPress}
|
||||||
onRetagArtistPress={this.onRetagArtistPress}
|
onRetagAuthorPress={this.onRetagAuthorPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<OrganizeArtistModal
|
<OrganizeAuthorModal
|
||||||
isOpen={this.state.isOrganizingArtistModalOpen}
|
isOpen={this.state.isOrganizingAuthorModalOpen}
|
||||||
authorIds={selectedAuthorIds}
|
authorIds={selectedAuthorIds}
|
||||||
onModalClose={this.onOrganizeArtistModalClose}
|
onModalClose={this.onOrganizeAuthorModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<RetagArtistModal
|
<RetagAuthorModal
|
||||||
isOpen={this.state.isRetaggingArtistModalOpen}
|
isOpen={this.state.isRetaggingAuthorModalOpen}
|
||||||
authorIds={selectedAuthorIds}
|
authorIds={selectedAuthorIds}
|
||||||
onModalClose={this.onRetagArtistModalClose}
|
onModalClose={this.onRetagAuthorModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</PageContent>
|
</PageContent>
|
||||||
@@ -277,7 +277,7 @@ class ArtistEditor extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistEditor.propTypes = {
|
AuthorEditor.propTypes = {
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
@@ -292,12 +292,12 @@ ArtistEditor.propTypes = {
|
|||||||
saveError: PropTypes.object,
|
saveError: PropTypes.object,
|
||||||
isDeleting: PropTypes.bool.isRequired,
|
isDeleting: PropTypes.bool.isRequired,
|
||||||
deleteError: PropTypes.object,
|
deleteError: PropTypes.object,
|
||||||
isOrganizingArtist: PropTypes.bool.isRequired,
|
isOrganizingAuthor: PropTypes.bool.isRequired,
|
||||||
isRetaggingArtist: PropTypes.bool.isRequired,
|
isRetaggingAuthor: PropTypes.bool.isRequired,
|
||||||
showMetadataProfile: PropTypes.bool.isRequired,
|
showMetadataProfile: PropTypes.bool.isRequired,
|
||||||
onSortPress: PropTypes.func.isRequired,
|
onSortPress: PropTypes.func.isRequired,
|
||||||
onFilterSelect: PropTypes.func.isRequired,
|
onFilterSelect: PropTypes.func.isRequired,
|
||||||
onSaveSelected: PropTypes.func.isRequired
|
onSaveSelected: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistEditor;
|
export default AuthorEditor;
|
||||||
@@ -4,38 +4,38 @@ import { connect } from 'react-redux';
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||||
import { setArtistEditorSort, setArtistEditorFilter, saveArtistEditor } from 'Store/Actions/artistEditorActions';
|
import { saveAuthorEditor, setAuthorEditorFilter, setAuthorEditorSort } from 'Store/Actions/authorEditorActions';
|
||||||
import { fetchRootFolders } from 'Store/Actions/settingsActions';
|
import { fetchRootFolders } from 'Store/Actions/settingsActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import ArtistEditor from './ArtistEditor';
|
import AuthorEditor from './AuthorEditor';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.settings.metadataProfiles,
|
(state) => state.settings.metadataProfiles,
|
||||||
createClientSideCollectionSelector('artist', 'artistEditor'),
|
createClientSideCollectionSelector('authors', 'authorEditor'),
|
||||||
createCommandExecutingSelector(commandNames.RENAME_ARTIST),
|
createCommandExecutingSelector(commandNames.RENAME_AUTHOR),
|
||||||
createCommandExecutingSelector(commandNames.RETAG_ARTIST),
|
createCommandExecutingSelector(commandNames.RETAG_AUTHOR),
|
||||||
(metadataProfiles, artist, isOrganizingArtist, isRetaggingArtist) => {
|
(metadataProfiles, author, isOrganizingAuthor, isRetaggingAuthor) => {
|
||||||
return {
|
return {
|
||||||
isOrganizingArtist,
|
isOrganizingAuthor,
|
||||||
isRetaggingArtist,
|
isRetaggingAuthor,
|
||||||
showMetadataProfile: metadataProfiles.items.length > 1,
|
showMetadataProfile: metadataProfiles.items.length > 1,
|
||||||
...artist
|
...author
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
dispatchSetArtistEditorSort: setArtistEditorSort,
|
dispatchSetAuthorEditorSort: setAuthorEditorSort,
|
||||||
dispatchSetArtistEditorFilter: setArtistEditorFilter,
|
dispatchSetAuthorEditorFilter: setAuthorEditorFilter,
|
||||||
dispatchSaveArtistEditor: saveArtistEditor,
|
dispatchSaveAuthorEditor: saveAuthorEditor,
|
||||||
dispatchFetchRootFolders: fetchRootFolders,
|
dispatchFetchRootFolders: fetchRootFolders,
|
||||||
dispatchExecuteCommand: executeCommand
|
dispatchExecuteCommand: executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArtistEditorConnector extends Component {
|
class AuthorEditorConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -48,20 +48,20 @@ class ArtistEditorConnector extends Component {
|
|||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onSortPress = (sortKey) => {
|
onSortPress = (sortKey) => {
|
||||||
this.props.dispatchSetArtistEditorSort({ sortKey });
|
this.props.dispatchSetAuthorEditorSort({ sortKey });
|
||||||
}
|
}
|
||||||
|
|
||||||
onFilterSelect = (selectedFilterKey) => {
|
onFilterSelect = (selectedFilterKey) => {
|
||||||
this.props.dispatchSetArtistEditorFilter({ selectedFilterKey });
|
this.props.dispatchSetAuthorEditorFilter({ selectedFilterKey });
|
||||||
}
|
}
|
||||||
|
|
||||||
onSaveSelected = (payload) => {
|
onSaveSelected = (payload) => {
|
||||||
this.props.dispatchSaveArtistEditor(payload);
|
this.props.dispatchSaveAuthorEditor(payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoveSelected = (payload) => {
|
onMoveSelected = (payload) => {
|
||||||
this.props.dispatchExecuteCommand({
|
this.props.dispatchExecuteCommand({
|
||||||
name: commandNames.MOVE_ARTIST,
|
name: commandNames.MOVE_AUTHOR,
|
||||||
...payload
|
...payload
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ class ArtistEditorConnector extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ArtistEditor
|
<AuthorEditor
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onSortPress={this.onSortPress}
|
onSortPress={this.onSortPress}
|
||||||
onFilterSelect={this.onFilterSelect}
|
onFilterSelect={this.onFilterSelect}
|
||||||
@@ -81,12 +81,12 @@ class ArtistEditorConnector extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistEditorConnector.propTypes = {
|
AuthorEditorConnector.propTypes = {
|
||||||
dispatchSetArtistEditorSort: PropTypes.func.isRequired,
|
dispatchSetAuthorEditorSort: PropTypes.func.isRequired,
|
||||||
dispatchSetArtistEditorFilter: PropTypes.func.isRequired,
|
dispatchSetAuthorEditorFilter: PropTypes.func.isRequired,
|
||||||
dispatchSaveArtistEditor: PropTypes.func.isRequired,
|
dispatchSaveAuthorEditor: PropTypes.func.isRequired,
|
||||||
dispatchFetchRootFolders: PropTypes.func.isRequired,
|
dispatchFetchRootFolders: PropTypes.func.isRequired,
|
||||||
dispatchExecuteCommand: PropTypes.func.isRequired
|
dispatchExecuteCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistEditorConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorEditorConnector);
|
||||||
@@ -1,24 +1,24 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { setArtistEditorFilter } from 'Store/Actions/artistEditorActions';
|
import { setAuthorEditorFilter } from 'Store/Actions/authorEditorActions';
|
||||||
import FilterModal from 'Components/Filter/FilterModal';
|
import FilterModal from 'Components/Filter/FilterModal';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.artist.items,
|
(state) => state.authors.items,
|
||||||
(state) => state.artistEditor.filterBuilderProps,
|
(state) => state.authorEditor.filterBuilderProps,
|
||||||
(sectionItems, filterBuilderProps) => {
|
(sectionItems, filterBuilderProps) => {
|
||||||
return {
|
return {
|
||||||
sectionItems,
|
sectionItems,
|
||||||
filterBuilderProps,
|
filterBuilderProps,
|
||||||
customFilterType: 'artistEditor'
|
customFilterType: 'authorEditor'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
dispatchSetFilter: setArtistEditorFilter
|
dispatchSetFilter: setAuthorEditorFilter
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(FilterModal);
|
export default connect(createMapStateToProps, mapDispatchToProps)(FilterModal);
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selectedArtistLabel {
|
.selectedAuthorLabel {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,15 +7,15 @@ import QualityProfileSelectInputConnector from 'Components/Form/QualityProfileSe
|
|||||||
import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector';
|
import RootFolderSelectInputConnector from 'Components/Form/RootFolderSelectInputConnector';
|
||||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||||
import MoveArtistModal from 'Artist/MoveArtist/MoveArtistModal';
|
import MoveAuthorModal from 'Author/MoveAuthor/MoveAuthorModal';
|
||||||
import TagsModal from './Tags/TagsModal';
|
import TagsModal from './Tags/TagsModal';
|
||||||
import DeleteArtistModal from './Delete/DeleteArtistModal';
|
import DeleteAuthorModal from './Delete/DeleteAuthorModal';
|
||||||
import ArtistEditorFooterLabel from './ArtistEditorFooterLabel';
|
import AuthorEditorFooterLabel from './AuthorEditorFooterLabel';
|
||||||
import styles from './ArtistEditorFooter.css';
|
import styles from './AuthorEditorFooter.css';
|
||||||
|
|
||||||
const NO_CHANGE = 'noChange';
|
const NO_CHANGE = 'noChange';
|
||||||
|
|
||||||
class ArtistEditorFooter extends Component {
|
class AuthorEditorFooter extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -27,10 +27,9 @@ class ArtistEditorFooter extends Component {
|
|||||||
monitored: NO_CHANGE,
|
monitored: NO_CHANGE,
|
||||||
qualityProfileId: NO_CHANGE,
|
qualityProfileId: NO_CHANGE,
|
||||||
metadataProfileId: NO_CHANGE,
|
metadataProfileId: NO_CHANGE,
|
||||||
albumFolder: NO_CHANGE,
|
|
||||||
rootFolderPath: NO_CHANGE,
|
rootFolderPath: NO_CHANGE,
|
||||||
savingTags: false,
|
savingTags: false,
|
||||||
isDeleteArtistModalOpen: false,
|
isDeleteAuthorModalOpen: false,
|
||||||
isTagsModalOpen: false,
|
isTagsModalOpen: false,
|
||||||
isConfirmMoveModalOpen: false,
|
isConfirmMoveModalOpen: false,
|
||||||
destinationRootFolder: null
|
destinationRootFolder: null
|
||||||
@@ -48,7 +47,6 @@ class ArtistEditorFooter extends Component {
|
|||||||
monitored: NO_CHANGE,
|
monitored: NO_CHANGE,
|
||||||
qualityProfileId: NO_CHANGE,
|
qualityProfileId: NO_CHANGE,
|
||||||
metadataProfileId: NO_CHANGE,
|
metadataProfileId: NO_CHANGE,
|
||||||
albumFolder: NO_CHANGE,
|
|
||||||
rootFolderPath: NO_CHANGE,
|
rootFolderPath: NO_CHANGE,
|
||||||
savingTags: false
|
savingTags: false
|
||||||
});
|
});
|
||||||
@@ -75,9 +73,6 @@ class ArtistEditorFooter extends Component {
|
|||||||
case 'monitored':
|
case 'monitored':
|
||||||
this.props.onSaveSelected({ [name]: value === 'monitored' });
|
this.props.onSaveSelected({ [name]: value === 'monitored' });
|
||||||
break;
|
break;
|
||||||
case 'albumFolder':
|
|
||||||
this.props.onSaveSelected({ [name]: value === 'yes' });
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
this.props.onSaveSelected({ [name]: value });
|
this.props.onSaveSelected({ [name]: value });
|
||||||
}
|
}
|
||||||
@@ -96,11 +91,11 @@ class ArtistEditorFooter extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onDeleteSelectedPress = () => {
|
onDeleteSelectedPress = () => {
|
||||||
this.setState({ isDeleteArtistModalOpen: true });
|
this.setState({ isDeleteAuthorModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeleteArtistModalClose = () => {
|
onDeleteAuthorModalClose = () => {
|
||||||
this.setState({ isDeleteArtistModalOpen: false });
|
this.setState({ isDeleteAuthorModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onTagsPress = () => {
|
onTagsPress = () => {
|
||||||
@@ -120,7 +115,7 @@ class ArtistEditorFooter extends Component {
|
|||||||
this.props.onSaveSelected({ rootFolderPath: this.state.destinationRootFolder });
|
this.props.onSaveSelected({ rootFolderPath: this.state.destinationRootFolder });
|
||||||
}
|
}
|
||||||
|
|
||||||
onMoveArtistPress = () => {
|
onMoveAuthorPress = () => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isConfirmMoveModalOpen: false,
|
isConfirmMoveModalOpen: false,
|
||||||
destinationRootFolder: null
|
destinationRootFolder: null
|
||||||
@@ -141,22 +136,21 @@ class ArtistEditorFooter extends Component {
|
|||||||
selectedCount,
|
selectedCount,
|
||||||
isSaving,
|
isSaving,
|
||||||
isDeleting,
|
isDeleting,
|
||||||
isOrganizingArtist,
|
isOrganizingAuthor,
|
||||||
isRetaggingArtist,
|
isRetaggingAuthor,
|
||||||
showMetadataProfile,
|
showMetadataProfile,
|
||||||
onOrganizeArtistPress,
|
onOrganizeAuthorPress,
|
||||||
onRetagArtistPress
|
onRetagAuthorPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
monitored,
|
monitored,
|
||||||
qualityProfileId,
|
qualityProfileId,
|
||||||
metadataProfileId,
|
metadataProfileId,
|
||||||
albumFolder,
|
|
||||||
rootFolderPath,
|
rootFolderPath,
|
||||||
savingTags,
|
savingTags,
|
||||||
isTagsModalOpen,
|
isTagsModalOpen,
|
||||||
isDeleteArtistModalOpen,
|
isDeleteAuthorModalOpen,
|
||||||
isConfirmMoveModalOpen,
|
isConfirmMoveModalOpen,
|
||||||
destinationRootFolder
|
destinationRootFolder
|
||||||
} = this.state;
|
} = this.state;
|
||||||
@@ -167,17 +161,11 @@ class ArtistEditorFooter extends Component {
|
|||||||
{ key: 'unmonitored', value: 'Unmonitored' }
|
{ key: 'unmonitored', value: 'Unmonitored' }
|
||||||
];
|
];
|
||||||
|
|
||||||
const albumFolderOptions = [
|
|
||||||
{ key: NO_CHANGE, value: 'No Change', disabled: true },
|
|
||||||
{ key: 'yes', value: 'Yes' },
|
|
||||||
{ key: 'no', value: 'No' }
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContentFooter>
|
<PageContentFooter>
|
||||||
<div className={styles.inputContainer}>
|
<div className={styles.inputContainer}>
|
||||||
<ArtistEditorFooterLabel
|
<AuthorEditorFooterLabel
|
||||||
label="Monitor Artist"
|
label="Monitor Author"
|
||||||
isSaving={isSaving && monitored !== NO_CHANGE}
|
isSaving={isSaving && monitored !== NO_CHANGE}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -191,7 +179,7 @@ class ArtistEditorFooter extends Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
<div className={styles.inputContainer}>
|
||||||
<ArtistEditorFooterLabel
|
<AuthorEditorFooterLabel
|
||||||
label="Quality Profile"
|
label="Quality Profile"
|
||||||
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
|
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
|
||||||
/>
|
/>
|
||||||
@@ -208,7 +196,7 @@ class ArtistEditorFooter extends Component {
|
|||||||
{
|
{
|
||||||
showMetadataProfile &&
|
showMetadataProfile &&
|
||||||
<div className={styles.inputContainer}>
|
<div className={styles.inputContainer}>
|
||||||
<ArtistEditorFooterLabel
|
<AuthorEditorFooterLabel
|
||||||
label="Metadata Profile"
|
label="Metadata Profile"
|
||||||
isSaving={isSaving && metadataProfileId !== NO_CHANGE}
|
isSaving={isSaving && metadataProfileId !== NO_CHANGE}
|
||||||
/>
|
/>
|
||||||
@@ -225,22 +213,7 @@ class ArtistEditorFooter extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
<div className={styles.inputContainer}>
|
||||||
<ArtistEditorFooterLabel
|
<AuthorEditorFooterLabel
|
||||||
label="Album Folder"
|
|
||||||
isSaving={isSaving && albumFolder !== NO_CHANGE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<SelectInput
|
|
||||||
name="albumFolder"
|
|
||||||
value={albumFolder}
|
|
||||||
values={albumFolderOptions}
|
|
||||||
isDisabled={!selectedCount}
|
|
||||||
onChange={this.onInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
|
||||||
<ArtistEditorFooterLabel
|
|
||||||
label="Root Folder"
|
label="Root Folder"
|
||||||
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
|
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
|
||||||
/>
|
/>
|
||||||
@@ -257,8 +230,8 @@ class ArtistEditorFooter extends Component {
|
|||||||
|
|
||||||
<div className={styles.buttonContainer}>
|
<div className={styles.buttonContainer}>
|
||||||
<div className={styles.buttonContainerContent}>
|
<div className={styles.buttonContainerContent}>
|
||||||
<ArtistEditorFooterLabel
|
<AuthorEditorFooterLabel
|
||||||
label={`${selectedCount} Artist(s) Selected`}
|
label={`${selectedCount} Author(s) Selected`}
|
||||||
isSaving={false}
|
isSaving={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -267,9 +240,9 @@ class ArtistEditorFooter extends Component {
|
|||||||
<SpinnerButton
|
<SpinnerButton
|
||||||
className={styles.organizeSelectedButton}
|
className={styles.organizeSelectedButton}
|
||||||
kind={kinds.WARNING}
|
kind={kinds.WARNING}
|
||||||
isSpinning={isOrganizingArtist}
|
isSpinning={isOrganizingAuthor}
|
||||||
isDisabled={!selectedCount || isOrganizingArtist || isRetaggingArtist}
|
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
|
||||||
onPress={onOrganizeArtistPress}
|
onPress={onOrganizeAuthorPress}
|
||||||
>
|
>
|
||||||
Rename Files
|
Rename Files
|
||||||
</SpinnerButton>
|
</SpinnerButton>
|
||||||
@@ -277,9 +250,9 @@ class ArtistEditorFooter extends Component {
|
|||||||
<SpinnerButton
|
<SpinnerButton
|
||||||
className={styles.organizeSelectedButton}
|
className={styles.organizeSelectedButton}
|
||||||
kind={kinds.WARNING}
|
kind={kinds.WARNING}
|
||||||
isSpinning={isRetaggingArtist}
|
isSpinning={isRetaggingAuthor}
|
||||||
isDisabled={!selectedCount || isOrganizingArtist || isRetaggingArtist}
|
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
|
||||||
onPress={onRetagArtistPress}
|
onPress={onRetagAuthorPress}
|
||||||
>
|
>
|
||||||
Write Metadata Tags
|
Write Metadata Tags
|
||||||
</SpinnerButton>
|
</SpinnerButton>
|
||||||
@@ -287,7 +260,7 @@ class ArtistEditorFooter extends Component {
|
|||||||
<SpinnerButton
|
<SpinnerButton
|
||||||
className={styles.tagsButton}
|
className={styles.tagsButton}
|
||||||
isSpinning={isSaving && savingTags}
|
isSpinning={isSaving && savingTags}
|
||||||
isDisabled={!selectedCount || isOrganizingArtist || isRetaggingArtist}
|
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
|
||||||
onPress={this.onTagsPress}
|
onPress={this.onTagsPress}
|
||||||
>
|
>
|
||||||
Set Readarr Tags
|
Set Readarr Tags
|
||||||
@@ -314,17 +287,17 @@ class ArtistEditorFooter extends Component {
|
|||||||
onModalClose={this.onTagsModalClose}
|
onModalClose={this.onTagsModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DeleteArtistModal
|
<DeleteAuthorModal
|
||||||
isOpen={isDeleteArtistModalOpen}
|
isOpen={isDeleteAuthorModalOpen}
|
||||||
authorIds={authorIds}
|
authorIds={authorIds}
|
||||||
onModalClose={this.onDeleteArtistModalClose}
|
onModalClose={this.onDeleteAuthorModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MoveArtistModal
|
<MoveAuthorModal
|
||||||
destinationRootFolder={destinationRootFolder}
|
destinationRootFolder={destinationRootFolder}
|
||||||
isOpen={isConfirmMoveModalOpen}
|
isOpen={isConfirmMoveModalOpen}
|
||||||
onSavePress={this.onSaveRootFolderPress}
|
onSavePress={this.onSaveRootFolderPress}
|
||||||
onMoveArtistPress={this.onMoveArtistPress}
|
onMoveAuthorPress={this.onMoveAuthorPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</PageContentFooter>
|
</PageContentFooter>
|
||||||
@@ -332,19 +305,19 @@ class ArtistEditorFooter extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistEditorFooter.propTypes = {
|
AuthorEditorFooter.propTypes = {
|
||||||
authorIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
authorIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
selectedCount: PropTypes.number.isRequired,
|
selectedCount: PropTypes.number.isRequired,
|
||||||
isSaving: PropTypes.bool.isRequired,
|
isSaving: PropTypes.bool.isRequired,
|
||||||
saveError: PropTypes.object,
|
saveError: PropTypes.object,
|
||||||
isDeleting: PropTypes.bool.isRequired,
|
isDeleting: PropTypes.bool.isRequired,
|
||||||
deleteError: PropTypes.object,
|
deleteError: PropTypes.object,
|
||||||
isOrganizingArtist: PropTypes.bool.isRequired,
|
isOrganizingAuthor: PropTypes.bool.isRequired,
|
||||||
isRetaggingArtist: PropTypes.bool.isRequired,
|
isRetaggingAuthor: PropTypes.bool.isRequired,
|
||||||
showMetadataProfile: PropTypes.bool.isRequired,
|
showMetadataProfile: PropTypes.bool.isRequired,
|
||||||
onSaveSelected: PropTypes.func.isRequired,
|
onSaveSelected: PropTypes.func.isRequired,
|
||||||
onOrganizeArtistPress: PropTypes.func.isRequired,
|
onOrganizeAuthorPress: PropTypes.func.isRequired,
|
||||||
onRetagArtistPress: PropTypes.func.isRequired
|
onRetagAuthorPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistEditorFooter;
|
export default AuthorEditorFooter;
|
||||||
@@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { icons } from 'Helpers/Props';
|
import { icons } from 'Helpers/Props';
|
||||||
import SpinnerIcon from 'Components/SpinnerIcon';
|
import SpinnerIcon from 'Components/SpinnerIcon';
|
||||||
import styles from './ArtistEditorFooterLabel.css';
|
import styles from './AuthorEditorFooterLabel.css';
|
||||||
|
|
||||||
function ArtistEditorFooterLabel(props) {
|
function AuthorEditorFooterLabel(props) {
|
||||||
const {
|
const {
|
||||||
className,
|
className,
|
||||||
label,
|
label,
|
||||||
@@ -27,14 +27,14 @@ function ArtistEditorFooterLabel(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistEditorFooterLabel.propTypes = {
|
AuthorEditorFooterLabel.propTypes = {
|
||||||
className: PropTypes.string.isRequired,
|
className: PropTypes.string.isRequired,
|
||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
isSaving: PropTypes.bool.isRequired
|
isSaving: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
ArtistEditorFooterLabel.defaultProps = {
|
AuthorEditorFooterLabel.defaultProps = {
|
||||||
className: styles.label
|
className: styles.label
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistEditorFooterLabel;
|
export default AuthorEditorFooterLabel;
|
||||||
@@ -5,16 +5,15 @@ import TagListConnector from 'Components/TagListConnector';
|
|||||||
import TableRow from 'Components/Table/TableRow';
|
import TableRow from 'Components/Table/TableRow';
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||||
import ArtistNameLink from 'Artist/ArtistNameLink';
|
import AuthorNameLink from 'Author/AuthorNameLink';
|
||||||
import ArtistStatusCell from 'Artist/Index/Table/ArtistStatusCell';
|
import AuthorStatusCell from 'Author/Index/Table/AuthorStatusCell';
|
||||||
import styles from './ArtistEditorRow.css';
|
|
||||||
|
|
||||||
class ArtistEditorRow extends Component {
|
class AuthorEditorRow extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onAlbumFolderChange = () => {
|
onBookFolderChange = () => {
|
||||||
// Mock handler to satisfy `onChange` being required for `CheckInput`.
|
// Mock handler to satisfy `onChange` being required for `CheckInput`.
|
||||||
//
|
//
|
||||||
}
|
}
|
||||||
@@ -27,8 +26,8 @@ class ArtistEditorRow extends Component {
|
|||||||
id,
|
id,
|
||||||
status,
|
status,
|
||||||
titleSlug,
|
titleSlug,
|
||||||
artistName,
|
authorName,
|
||||||
artistType,
|
authorType,
|
||||||
monitored,
|
monitored,
|
||||||
metadataProfile,
|
metadataProfile,
|
||||||
qualityProfile,
|
qualityProfile,
|
||||||
@@ -47,16 +46,16 @@ class ArtistEditorRow extends Component {
|
|||||||
onSelectedChange={onSelectedChange}
|
onSelectedChange={onSelectedChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ArtistStatusCell
|
<AuthorStatusCell
|
||||||
artistType={artistType}
|
authorType={authorType}
|
||||||
monitored={monitored}
|
monitored={monitored}
|
||||||
status={status}
|
status={status}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TableRowCell className={styles.title}>
|
<TableRowCell>
|
||||||
<ArtistNameLink
|
<AuthorNameLink
|
||||||
titleSlug={titleSlug}
|
titleSlug={titleSlug}
|
||||||
artistName={artistName}
|
authorName={authorName}
|
||||||
/>
|
/>
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
@@ -85,12 +84,12 @@ class ArtistEditorRow extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistEditorRow.propTypes = {
|
AuthorEditorRow.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
status: PropTypes.string.isRequired,
|
status: PropTypes.string.isRequired,
|
||||||
titleSlug: PropTypes.string.isRequired,
|
titleSlug: PropTypes.string.isRequired,
|
||||||
artistName: PropTypes.string.isRequired,
|
authorName: PropTypes.string.isRequired,
|
||||||
artistType: PropTypes.string,
|
authorType: PropTypes.string,
|
||||||
monitored: PropTypes.bool.isRequired,
|
monitored: PropTypes.bool.isRequired,
|
||||||
metadataProfile: PropTypes.object.isRequired,
|
metadataProfile: PropTypes.object.isRequired,
|
||||||
qualityProfile: PropTypes.object.isRequired,
|
qualityProfile: PropTypes.object.isRequired,
|
||||||
@@ -101,8 +100,8 @@ ArtistEditorRow.propTypes = {
|
|||||||
onSelectedChange: PropTypes.func.isRequired
|
onSelectedChange: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
ArtistEditorRow.defaultProps = {
|
AuthorEditorRow.defaultProps = {
|
||||||
tags: []
|
tags: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistEditorRow;
|
export default AuthorEditorRow;
|
||||||
@@ -4,7 +4,7 @@ import { connect } from 'react-redux';
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createMetadataProfileSelector from 'Store/Selectors/createMetadataProfileSelector';
|
import createMetadataProfileSelector from 'Store/Selectors/createMetadataProfileSelector';
|
||||||
import createQualityProfileSelector from 'Store/Selectors/createQualityProfileSelector';
|
import createQualityProfileSelector from 'Store/Selectors/createQualityProfileSelector';
|
||||||
import ArtistEditorRow from './ArtistEditorRow';
|
import AuthorEditorRow from './AuthorEditorRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
@@ -19,16 +19,16 @@ function createMapStateToProps() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function ArtistEditorRowConnector(props) {
|
function AuthorEditorRowConnector(props) {
|
||||||
return (
|
return (
|
||||||
<ArtistEditorRow
|
<AuthorEditorRow
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistEditorRowConnector.propTypes = {
|
AuthorEditorRowConnector.propTypes = {
|
||||||
qualityProfileId: PropTypes.number.isRequired
|
qualityProfileId: PropTypes.number.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps)(ArtistEditorRowConnector);
|
export default connect(createMapStateToProps)(AuthorEditorRowConnector);
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Modal from 'Components/Modal/Modal';
|
import Modal from 'Components/Modal/Modal';
|
||||||
import AddNewArtistModalContentConnector from './AddNewArtistModalContentConnector';
|
import DeleteAuthorModalContentConnector from './DeleteAuthorModalContentConnector';
|
||||||
|
|
||||||
function AddNewArtistModal(props) {
|
function DeleteAuthorModal(props) {
|
||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
onModalClose,
|
onModalClose,
|
||||||
@@ -15,7 +15,7 @@ function AddNewArtistModal(props) {
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
>
|
>
|
||||||
<AddNewArtistModalContentConnector
|
<DeleteAuthorModalContentConnector
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -23,9 +23,9 @@ function AddNewArtistModal(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
AddNewArtistModal.propTypes = {
|
DeleteAuthorModal.propTypes = {
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddNewArtistModal;
|
export default DeleteAuthorModal;
|
||||||
@@ -9,9 +9,9 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import ModalBody from 'Components/Modal/ModalBody';
|
import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import styles from './DeleteArtistModalContent.css';
|
import styles from './DeleteAuthorModalContent.css';
|
||||||
|
|
||||||
class DeleteArtistModalContent extends Component {
|
class DeleteAuthorModalContent extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -31,7 +31,7 @@ class DeleteArtistModalContent extends Component {
|
|||||||
this.setState({ deleteFiles: value });
|
this.setState({ deleteFiles: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onDeleteArtistConfirmed = () => {
|
onDeleteAuthorConfirmed = () => {
|
||||||
const deleteFiles = this.state.deleteFiles;
|
const deleteFiles = this.state.deleteFiles;
|
||||||
|
|
||||||
this.setState({ deleteFiles: false });
|
this.setState({ deleteFiles: false });
|
||||||
@@ -43,7 +43,7 @@ class DeleteArtistModalContent extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
artist,
|
author,
|
||||||
onModalClose
|
onModalClose
|
||||||
} = this.props;
|
} = this.props;
|
||||||
const deleteFiles = this.state.deleteFiles;
|
const deleteFiles = this.state.deleteFiles;
|
||||||
@@ -51,19 +51,19 @@ class DeleteArtistModalContent extends Component {
|
|||||||
return (
|
return (
|
||||||
<ModalContent onModalClose={onModalClose}>
|
<ModalContent onModalClose={onModalClose}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
Delete Selected Artist
|
Delete Selected Author
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<div>
|
<div>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>{`Delete Artist Folder${artist.length > 1 ? 's' : ''}`}</FormLabel>
|
<FormLabel>{`Delete Author Folder${author.length > 1 ? 's' : ''}`}</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="deleteFiles"
|
name="deleteFiles"
|
||||||
value={deleteFiles}
|
value={deleteFiles}
|
||||||
helpText={`Delete Artist Folder${artist.length > 1 ? 's' : ''} and all contents`}
|
helpText={`Delete Author Folder${author.length > 1 ? 's' : ''} and all contents`}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onChange={this.onDeleteFilesChange}
|
onChange={this.onDeleteFilesChange}
|
||||||
/>
|
/>
|
||||||
@@ -71,15 +71,15 @@ class DeleteArtistModalContent extends Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.message}>
|
<div className={styles.message}>
|
||||||
{`Are you sure you want to delete ${artist.length} selected artist${artist.length > 1 ? 's' : ''}${deleteFiles ? ' and all contents' : ''}?`}
|
{`Are you sure you want to delete ${author.length} selected author${author.length > 1 ? 's' : ''}${deleteFiles ? ' and all contents' : ''}?`}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
artist.map((s) => {
|
author.map((s) => {
|
||||||
return (
|
return (
|
||||||
<li key={s.artistName}>
|
<li key={s.authorName}>
|
||||||
<span>{s.artistName}</span>
|
<span>{s.authorName}</span>
|
||||||
|
|
||||||
{
|
{
|
||||||
deleteFiles &&
|
deleteFiles &&
|
||||||
@@ -104,7 +104,7 @@ class DeleteArtistModalContent extends Component {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={this.onDeleteArtistConfirmed}
|
onPress={this.onDeleteAuthorConfirmed}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
@@ -114,10 +114,10 @@ class DeleteArtistModalContent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeleteArtistModalContent.propTypes = {
|
DeleteAuthorModalContent.propTypes = {
|
||||||
artist: PropTypes.arrayOf(PropTypes.object).isRequired,
|
author: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
onDeleteSelectedPress: PropTypes.func.isRequired
|
onDeleteSelectedPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default DeleteArtistModalContent;
|
export default DeleteAuthorModalContent;
|
||||||
@@ -1,29 +1,29 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
|
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
|
||||||
import { bulkDeleteArtist } from 'Store/Actions/artistEditorActions';
|
import { bulkDeleteAuthor } from 'Store/Actions/authorEditorActions';
|
||||||
import DeleteArtistModalContent from './DeleteArtistModalContent';
|
import DeleteAuthorModalContent from './DeleteAuthorModalContent';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { authorIds }) => authorIds,
|
(state, { authorIds }) => authorIds,
|
||||||
createAllArtistSelector(),
|
createAllAuthorSelector(),
|
||||||
(authorIds, allArtists) => {
|
(authorIds, allAuthors) => {
|
||||||
const selectedArtist = _.intersectionWith(allArtists, authorIds, (s, id) => {
|
const selectedAuthor = _.intersectionWith(allAuthors, authorIds, (s, id) => {
|
||||||
return s.id === id;
|
return s.id === id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const sortedArtist = _.orderBy(selectedArtist, 'sortName');
|
const sortedAuthor = _.orderBy(selectedAuthor, 'sortName');
|
||||||
const artist = _.map(sortedArtist, (s) => {
|
const author = _.map(sortedAuthor, (s) => {
|
||||||
return {
|
return {
|
||||||
artistName: s.artistName,
|
authorName: s.authorName,
|
||||||
path: s.path
|
path: s.path
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
artist
|
author
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -32,7 +32,7 @@ function createMapStateToProps() {
|
|||||||
function createMapDispatchToProps(dispatch, props) {
|
function createMapDispatchToProps(dispatch, props) {
|
||||||
return {
|
return {
|
||||||
onDeleteSelectedPress(deleteFiles) {
|
onDeleteSelectedPress(deleteFiles) {
|
||||||
dispatch(bulkDeleteArtist({
|
dispatch(bulkDeleteAuthor({
|
||||||
authorIds: props.authorIds,
|
authorIds: props.authorIds,
|
||||||
deleteFiles
|
deleteFiles
|
||||||
}));
|
}));
|
||||||
@@ -42,4 +42,4 @@ function createMapDispatchToProps(dispatch, props) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(createMapStateToProps, createMapDispatchToProps)(DeleteArtistModalContent);
|
export default connect(createMapStateToProps, createMapDispatchToProps)(DeleteAuthorModalContent);
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Modal from 'Components/Modal/Modal';
|
import Modal from 'Components/Modal/Modal';
|
||||||
import OrganizeArtistModalContentConnector from './OrganizeArtistModalContentConnector';
|
import OrganizeAuthorModalContentConnector from './OrganizeAuthorModalContentConnector';
|
||||||
|
|
||||||
function OrganizeArtistModal(props) {
|
function OrganizeAuthorModal(props) {
|
||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
onModalClose,
|
onModalClose,
|
||||||
@@ -15,7 +15,7 @@ function OrganizeArtistModal(props) {
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
>
|
>
|
||||||
<OrganizeArtistModalContentConnector
|
<OrganizeAuthorModalContentConnector
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -23,9 +23,9 @@ function OrganizeArtistModal(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
OrganizeArtistModal.propTypes = {
|
OrganizeAuthorModal.propTypes = {
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default OrganizeArtistModal;
|
export default OrganizeAuthorModal;
|
||||||
@@ -8,24 +8,24 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import ModalBody from 'Components/Modal/ModalBody';
|
import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import styles from './OrganizeArtistModalContent.css';
|
import styles from './OrganizeAuthorModalContent.css';
|
||||||
|
|
||||||
function OrganizeArtistModalContent(props) {
|
function OrganizeAuthorModalContent(props) {
|
||||||
const {
|
const {
|
||||||
artistNames,
|
authorNames,
|
||||||
onModalClose,
|
onModalClose,
|
||||||
onOrganizeArtistPress
|
onOrganizeAuthorPress
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalContent onModalClose={onModalClose}>
|
<ModalContent onModalClose={onModalClose}>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
Organize Selected Artist
|
Organize Selected Author
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Alert>
|
<Alert>
|
||||||
Tip: To preview a rename... select "Cancel" then click any artist name and use the
|
Tip: To preview a rename... select "Cancel" then click any author name and use the
|
||||||
<Icon
|
<Icon
|
||||||
className={styles.renameIcon}
|
className={styles.renameIcon}
|
||||||
name={icons.ORGANIZE}
|
name={icons.ORGANIZE}
|
||||||
@@ -33,15 +33,15 @@ function OrganizeArtistModalContent(props) {
|
|||||||
</Alert>
|
</Alert>
|
||||||
|
|
||||||
<div className={styles.message}>
|
<div className={styles.message}>
|
||||||
Are you sure you want to organize all files in the {artistNames.length} selected artist?
|
Are you sure you want to organize all files in the {authorNames.length} selected author?
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
artistNames.map((artistName) => {
|
authorNames.map((authorName) => {
|
||||||
return (
|
return (
|
||||||
<li key={artistName}>
|
<li key={authorName}>
|
||||||
{artistName}
|
{authorName}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -56,7 +56,7 @@ function OrganizeArtistModalContent(props) {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={onOrganizeArtistPress}
|
onPress={onOrganizeAuthorPress}
|
||||||
>
|
>
|
||||||
Organize
|
Organize
|
||||||
</Button>
|
</Button>
|
||||||
@@ -65,10 +65,10 @@ function OrganizeArtistModalContent(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
OrganizeArtistModalContent.propTypes = {
|
OrganizeAuthorModalContent.propTypes = {
|
||||||
artistNames: PropTypes.arrayOf(PropTypes.string).isRequired,
|
authorNames: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
onOrganizeArtistPress: PropTypes.func.isRequired
|
onOrganizeAuthorPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default OrganizeArtistModalContent;
|
export default OrganizeAuthorModalContent;
|
||||||
@@ -3,25 +3,25 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
|
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import OrganizeArtistModalContent from './OrganizeArtistModalContent';
|
import OrganizeAuthorModalContent from './OrganizeAuthorModalContent';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { authorIds }) => authorIds,
|
(state, { authorIds }) => authorIds,
|
||||||
createAllArtistSelector(),
|
createAllAuthorSelector(),
|
||||||
(authorIds, allArtists) => {
|
(authorIds, allAuthors) => {
|
||||||
const artist = _.intersectionWith(allArtists, authorIds, (s, id) => {
|
const author = _.intersectionWith(allAuthors, authorIds, (s, id) => {
|
||||||
return s.id === id;
|
return s.id === id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const sortedArtist = _.orderBy(artist, 'sortName');
|
const sortedAuthor = _.orderBy(author, 'sortName');
|
||||||
const artistNames = _.map(sortedArtist, 'artistName');
|
const authorNames = _.map(sortedAuthor, 'authorName');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
artistNames
|
authorNames
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -31,14 +31,14 @@ const mapDispatchToProps = {
|
|||||||
executeCommand
|
executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class OrganizeArtistModalContentConnector extends Component {
|
class OrganizeAuthorModalContentConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onOrganizeArtistPress = () => {
|
onOrganizeAuthorPress = () => {
|
||||||
this.props.executeCommand({
|
this.props.executeCommand({
|
||||||
name: commandNames.RENAME_ARTIST,
|
name: commandNames.RENAME_AUTHOR,
|
||||||
authorIds: this.props.authorIds
|
authorIds: this.props.authorIds
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -50,18 +50,18 @@ class OrganizeArtistModalContentConnector extends Component {
|
|||||||
|
|
||||||
render(props) {
|
render(props) {
|
||||||
return (
|
return (
|
||||||
<OrganizeArtistModalContent
|
<OrganizeAuthorModalContent
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onOrganizeArtistPress={this.onOrganizeArtistPress}
|
onOrganizeAuthorPress={this.onOrganizeAuthorPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OrganizeArtistModalContentConnector.propTypes = {
|
OrganizeAuthorModalContentConnector.propTypes = {
|
||||||
authorIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
authorIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
executeCommand: PropTypes.func.isRequired
|
executeCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(OrganizeArtistModalContentConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(OrganizeAuthorModalContentConnector);
|
||||||
@@ -49,7 +49,7 @@ class TagsModalContent extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
artistTags,
|
authorTags,
|
||||||
tagList,
|
tagList,
|
||||||
onModalClose
|
onModalClose
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@@ -93,7 +93,7 @@ class TagsModalContent extends Component {
|
|||||||
value={applyTags}
|
value={applyTags}
|
||||||
values={applyTagsOptions}
|
values={applyTagsOptions}
|
||||||
helpTexts={[
|
helpTexts={[
|
||||||
'How to apply tags to the selected artist',
|
'How to apply tags to the selected author',
|
||||||
'Add: Add the tags the existing list of tags',
|
'Add: Add the tags the existing list of tags',
|
||||||
'Remove: Remove the entered tags',
|
'Remove: Remove the entered tags',
|
||||||
'Replace: Replace the tags with the entered tags (enter no tags to clear all tags)'
|
'Replace: Replace the tags with the entered tags (enter no tags to clear all tags)'
|
||||||
@@ -107,7 +107,7 @@ class TagsModalContent extends Component {
|
|||||||
|
|
||||||
<div className={styles.result}>
|
<div className={styles.result}>
|
||||||
{
|
{
|
||||||
artistTags.map((t) => {
|
authorTags.map((t) => {
|
||||||
const tag = _.find(tagList, { id: t });
|
const tag = _.find(tagList, { id: t });
|
||||||
|
|
||||||
if (!tag) {
|
if (!tag) {
|
||||||
@@ -139,7 +139,7 @@ class TagsModalContent extends Component {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (artistTags.indexOf(t) > -1) {
|
if (authorTags.indexOf(t) > -1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ class TagsModalContent extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TagsModalContent.propTypes = {
|
TagsModalContent.propTypes = {
|
||||||
artistTags: PropTypes.arrayOf(PropTypes.number).isRequired,
|
authorTags: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||||
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
|
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired,
|
onModalClose: PropTypes.func.isRequired,
|
||||||
onApplyTagsPress: PropTypes.func.isRequired
|
onApplyTagsPress: PropTypes.func.isRequired
|
||||||
@@ -1,24 +1,24 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createAllArtistSelector from 'Store/Selectors/createAllArtistSelector';
|
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
|
||||||
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
||||||
import TagsModalContent from './TagsModalContent';
|
import TagsModalContent from './TagsModalContent';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state, { authorIds }) => authorIds,
|
(state, { authorIds }) => authorIds,
|
||||||
createAllArtistSelector(),
|
createAllAuthorSelector(),
|
||||||
createTagsSelector(),
|
createTagsSelector(),
|
||||||
(authorIds, allArtists, tagList) => {
|
(authorIds, allAuthors, tagList) => {
|
||||||
const artist = _.intersectionWith(allArtists, authorIds, (s, id) => {
|
const author = _.intersectionWith(allAuthors, authorIds, (s, id) => {
|
||||||
return s.id === id;
|
return s.id === id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const artistTags = _.uniq(_.concat(..._.map(artist, 'tags')));
|
const authorTags = _.uniq(_.concat(..._.map(author, 'tags')));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
artistTags,
|
authorTags,
|
||||||
tagList
|
tagList
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2,24 +2,24 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { fetchArtistHistory, clearArtistHistory, artistHistoryMarkAsFailed } from 'Store/Actions/artistHistoryActions';
|
import { authorHistoryMarkAsFailed, clearAuthorHistory, fetchAuthorHistory } from 'Store/Actions/authorHistoryActions';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.artistHistory,
|
(state) => state.authorHistory,
|
||||||
(artistHistory) => {
|
(authorHistory) => {
|
||||||
return artistHistory;
|
return authorHistory;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
fetchArtistHistory,
|
fetchAuthorHistory,
|
||||||
clearArtistHistory,
|
clearAuthorHistory,
|
||||||
artistHistoryMarkAsFailed
|
authorHistoryMarkAsFailed
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArtistHistoryContentConnector extends Component {
|
class AuthorHistoryContentConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -30,14 +30,14 @@ class ArtistHistoryContentConnector extends Component {
|
|||||||
bookId
|
bookId
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this.props.fetchArtistHistory({
|
this.props.fetchAuthorHistory({
|
||||||
authorId,
|
authorId,
|
||||||
bookId
|
bookId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.props.clearArtistHistory();
|
this.props.clearAuthorHistory();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -49,7 +49,7 @@ class ArtistHistoryContentConnector extends Component {
|
|||||||
bookId
|
bookId
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
this.props.artistHistoryMarkAsFailed({
|
this.props.authorHistoryMarkAsFailed({
|
||||||
historyId,
|
historyId,
|
||||||
authorId,
|
authorId,
|
||||||
bookId
|
bookId
|
||||||
@@ -74,13 +74,13 @@ class ArtistHistoryContentConnector extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistHistoryContentConnector.propTypes = {
|
AuthorHistoryContentConnector.propTypes = {
|
||||||
component: PropTypes.elementType.isRequired,
|
component: PropTypes.elementType.isRequired,
|
||||||
authorId: PropTypes.number.isRequired,
|
authorId: PropTypes.number.isRequired,
|
||||||
bookId: PropTypes.number,
|
bookId: PropTypes.number,
|
||||||
fetchArtistHistory: PropTypes.func.isRequired,
|
fetchAuthorHistory: PropTypes.func.isRequired,
|
||||||
clearArtistHistory: PropTypes.func.isRequired,
|
clearAuthorHistory: PropTypes.func.isRequired,
|
||||||
artistHistoryMarkAsFailed: PropTypes.func.isRequired
|
authorHistoryMarkAsFailed: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistHistoryContentConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorHistoryContentConnector);
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Modal from 'Components/Modal/Modal';
|
import Modal from 'Components/Modal/Modal';
|
||||||
import ArtistHistoryContentConnector from './ArtistHistoryContentConnector';
|
import AuthorHistoryContentConnector from './AuthorHistoryContentConnector';
|
||||||
import ArtistHistoryModalContent from './ArtistHistoryModalContent';
|
import AuthorHistoryModalContent from './AuthorHistoryModalContent';
|
||||||
|
|
||||||
function ArtistHistoryModal(props) {
|
function AuthorHistoryModal(props) {
|
||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
onModalClose,
|
onModalClose,
|
||||||
@@ -16,8 +16,8 @@ function ArtistHistoryModal(props) {
|
|||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
>
|
>
|
||||||
<ArtistHistoryContentConnector
|
<AuthorHistoryContentConnector
|
||||||
component={ArtistHistoryModalContent}
|
component={AuthorHistoryModalContent}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -25,9 +25,9 @@ function ArtistHistoryModal(props) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistHistoryModal.propTypes = {
|
AuthorHistoryModal.propTypes = {
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistHistoryModal;
|
export default AuthorHistoryModal;
|
||||||
@@ -5,9 +5,9 @@ import ModalContent from 'Components/Modal/ModalContent';
|
|||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import ModalBody from 'Components/Modal/ModalBody';
|
import ModalBody from 'Components/Modal/ModalBody';
|
||||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||||
import ArtistHistoryTableContent from './ArtistHistoryTableContent';
|
import AuthorHistoryTableContent from './AuthorHistoryTableContent';
|
||||||
|
|
||||||
class ArtistHistoryModalContent extends Component {
|
class AuthorHistoryModalContent extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
@@ -24,7 +24,7 @@ class ArtistHistoryModalContent extends Component {
|
|||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<ArtistHistoryTableContent
|
<AuthorHistoryTableContent
|
||||||
{...this.props}
|
{...this.props}
|
||||||
/>
|
/>
|
||||||
</ModalBody>
|
</ModalBody>
|
||||||
@@ -39,8 +39,8 @@ class ArtistHistoryModalContent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistHistoryModalContent.propTypes = {
|
AuthorHistoryModalContent.propTypes = {
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistHistoryModalContent;
|
export default AuthorHistoryModalContent;
|
||||||
@@ -8,10 +8,10 @@ import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellCo
|
|||||||
import TableRow from 'Components/Table/TableRow';
|
import TableRow from 'Components/Table/TableRow';
|
||||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||||
import Popover from 'Components/Tooltip/Popover';
|
import Popover from 'Components/Tooltip/Popover';
|
||||||
import TrackQuality from 'Album/TrackQuality';
|
import BookQuality from 'Book/BookQuality';
|
||||||
import HistoryDetailsConnector from 'Activity/History/Details/HistoryDetailsConnector';
|
import HistoryDetailsConnector from 'Activity/History/Details/HistoryDetailsConnector';
|
||||||
import HistoryEventTypeCell from 'Activity/History/HistoryEventTypeCell';
|
import HistoryEventTypeCell from 'Activity/History/HistoryEventTypeCell';
|
||||||
import styles from './ArtistHistoryRow.css';
|
import styles from './AuthorHistoryRow.css';
|
||||||
|
|
||||||
function getTitle(eventType) {
|
function getTitle(eventType) {
|
||||||
switch (eventType) {
|
switch (eventType) {
|
||||||
@@ -19,24 +19,24 @@ function getTitle(eventType) {
|
|||||||
return 'Grabbed';
|
return 'Grabbed';
|
||||||
case 'downloadImported':
|
case 'downloadImported':
|
||||||
return 'Download Completed';
|
return 'Download Completed';
|
||||||
case 'trackFileImported':
|
case 'bookFileImported':
|
||||||
return 'Track Imported';
|
return 'Book Imported';
|
||||||
case 'downloadFailed':
|
case 'downloadFailed':
|
||||||
return 'Download Failed';
|
return 'Download Failed';
|
||||||
case 'trackFileDeleted':
|
case 'bookFileDeleted':
|
||||||
return 'Track File Deleted';
|
return 'Book File Deleted';
|
||||||
case 'trackFileRenamed':
|
case 'bookFileRenamed':
|
||||||
return 'Track File Renamed';
|
return 'Book File Renamed';
|
||||||
case 'trackFileRetagged':
|
case 'bookFileRetagged':
|
||||||
return 'Track File Tags Updated';
|
return 'Book File Tags Updated';
|
||||||
case 'albumImportIncomplete':
|
case 'bookImportIncomplete':
|
||||||
return 'Album Import Incomplete';
|
return 'Book Import Incomplete';
|
||||||
default:
|
default:
|
||||||
return 'Unknown';
|
return 'Unknown';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistHistoryRow extends Component {
|
class AuthorHistoryRow extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -76,7 +76,7 @@ class ArtistHistoryRow extends Component {
|
|||||||
qualityCutoffNotMet,
|
qualityCutoffNotMet,
|
||||||
date,
|
date,
|
||||||
data,
|
data,
|
||||||
album
|
book
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -91,7 +91,7 @@ class ArtistHistoryRow extends Component {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<TableRowCell key={name}>
|
<TableRowCell key={name}>
|
||||||
{album.title}
|
{book.title}
|
||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
<TableRowCell>
|
<TableRowCell>
|
||||||
@@ -99,7 +99,7 @@ class ArtistHistoryRow extends Component {
|
|||||||
</TableRowCell>
|
</TableRowCell>
|
||||||
|
|
||||||
<TableRowCell>
|
<TableRowCell>
|
||||||
<TrackQuality
|
<BookQuality
|
||||||
quality={quality}
|
quality={quality}
|
||||||
isCutoffNotMet={qualityCutoffNotMet}
|
isCutoffNotMet={qualityCutoffNotMet}
|
||||||
/>
|
/>
|
||||||
@@ -153,7 +153,7 @@ class ArtistHistoryRow extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistHistoryRow.propTypes = {
|
AuthorHistoryRow.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
eventType: PropTypes.string.isRequired,
|
eventType: PropTypes.string.isRequired,
|
||||||
sourceTitle: PropTypes.string.isRequired,
|
sourceTitle: PropTypes.string.isRequired,
|
||||||
@@ -161,10 +161,10 @@ ArtistHistoryRow.propTypes = {
|
|||||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||||
date: PropTypes.string.isRequired,
|
date: PropTypes.string.isRequired,
|
||||||
data: PropTypes.object.isRequired,
|
data: PropTypes.object.isRequired,
|
||||||
fullArtist: PropTypes.bool.isRequired,
|
fullAuthor: PropTypes.bool.isRequired,
|
||||||
artist: PropTypes.object.isRequired,
|
author: PropTypes.object.isRequired,
|
||||||
album: PropTypes.object.isRequired,
|
book: PropTypes.object.isRequired,
|
||||||
onMarkAsFailedPress: PropTypes.func.isRequired
|
onMarkAsFailedPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistHistoryRow;
|
export default AuthorHistoryRow;
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { fetchHistory, markAsFailed } from 'Store/Actions/historyActions';
|
import { fetchHistory, markAsFailed } from 'Store/Actions/historyActions';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import createAlbumSelector from 'Store/Selectors/createAlbumSelector';
|
import createBookSelector from 'Store/Selectors/createBookSelector';
|
||||||
import ArtistHistoryRow from './ArtistHistoryRow';
|
import AuthorHistoryRow from './AuthorHistoryRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
createAlbumSelector(),
|
createBookSelector(),
|
||||||
(artist, album) => {
|
(author, book) => {
|
||||||
return {
|
return {
|
||||||
artist,
|
author,
|
||||||
album
|
book
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -23,4 +23,4 @@ const mapDispatchToProps = {
|
|||||||
markAsFailed
|
markAsFailed
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistHistoryRow);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorHistoryRow);
|
||||||
21
frontend/src/Author/History/AuthorHistoryTable.js
Normal file
21
frontend/src/Author/History/AuthorHistoryTable.js
Normal file
@@ -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;
|
||||||
@@ -3,7 +3,7 @@ import React, { Component } from 'react';
|
|||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
import Table from 'Components/Table/Table';
|
import Table from 'Components/Table/Table';
|
||||||
import TableBody from 'Components/Table/TableBody';
|
import TableBody from 'Components/Table/TableBody';
|
||||||
import ArtistHistoryRowConnector from './ArtistHistoryRowConnector';
|
import AuthorHistoryRowConnector from './AuthorHistoryRowConnector';
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -11,8 +11,8 @@ const columns = [
|
|||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'album',
|
name: 'book',
|
||||||
label: 'Album',
|
label: 'Book',
|
||||||
isVisible: true
|
isVisible: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -42,7 +42,7 @@ const columns = [
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
class ArtistHistoryTableContent extends Component {
|
class AuthorHistoryTableContent extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
@@ -57,7 +57,7 @@ class ArtistHistoryTableContent extends Component {
|
|||||||
onMarkAsFailedPress
|
onMarkAsFailedPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const fullArtist = bookId == null;
|
const fullAuthor = bookId == null;
|
||||||
const hasItems = !!items.length;
|
const hasItems = !!items.length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -84,9 +84,9 @@ class ArtistHistoryTableContent extends Component {
|
|||||||
{
|
{
|
||||||
items.map((item) => {
|
items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<ArtistHistoryRowConnector
|
<AuthorHistoryRowConnector
|
||||||
key={item.id}
|
key={item.id}
|
||||||
fullArtist={fullArtist}
|
fullAuthor={fullAuthor}
|
||||||
{...item}
|
{...item}
|
||||||
onMarkAsFailedPress={onMarkAsFailedPress}
|
onMarkAsFailedPress={onMarkAsFailedPress}
|
||||||
/>
|
/>
|
||||||
@@ -101,7 +101,7 @@ class ArtistHistoryTableContent extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistHistoryTableContent.propTypes = {
|
AuthorHistoryTableContent.propTypes = {
|
||||||
bookId: PropTypes.number,
|
bookId: PropTypes.number,
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
@@ -110,4 +110,4 @@ ArtistHistoryTableContent.propTypes = {
|
|||||||
onMarkAsFailedPress: PropTypes.func.isRequired
|
onMarkAsFailedPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistHistoryTableContent;
|
export default AuthorHistoryTableContent;
|
||||||
@@ -13,38 +13,38 @@ import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
|||||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||||
import NoArtist from 'Artist/NoArtist';
|
import NoAuthor from 'Author/NoAuthor';
|
||||||
import ArtistIndexTableConnector from './Table/ArtistIndexTableConnector';
|
import AuthorIndexTableConnector from './Table/AuthorIndexTableConnector';
|
||||||
import ArtistIndexTableOptionsConnector from './Table/ArtistIndexTableOptionsConnector';
|
import AuthorIndexTableOptionsConnector from './Table/AuthorIndexTableOptionsConnector';
|
||||||
import ArtistIndexPosterOptionsModal from './Posters/Options/ArtistIndexPosterOptionsModal';
|
import AuthorIndexPosterOptionsModal from './Posters/Options/AuthorIndexPosterOptionsModal';
|
||||||
import ArtistIndexPostersConnector from './Posters/ArtistIndexPostersConnector';
|
import AuthorIndexPostersConnector from './Posters/AuthorIndexPostersConnector';
|
||||||
import ArtistIndexBannerOptionsModal from './Banners/Options/ArtistIndexBannerOptionsModal';
|
import AuthorIndexBannerOptionsModal from './Banners/Options/AuthorIndexBannerOptionsModal';
|
||||||
import ArtistIndexBannersConnector from './Banners/ArtistIndexBannersConnector';
|
import AuthorIndexBannersConnector from './Banners/AuthorIndexBannersConnector';
|
||||||
import ArtistIndexOverviewOptionsModal from './Overview/Options/ArtistIndexOverviewOptionsModal';
|
import AuthorIndexOverviewOptionsModal from './Overview/Options/AuthorIndexOverviewOptionsModal';
|
||||||
import ArtistIndexOverviewsConnector from './Overview/ArtistIndexOverviewsConnector';
|
import AuthorIndexOverviewsConnector from './Overview/AuthorIndexOverviewsConnector';
|
||||||
import ArtistIndexFooterConnector from './ArtistIndexFooterConnector';
|
import AuthorIndexFooterConnector from './AuthorIndexFooterConnector';
|
||||||
import ArtistIndexFilterMenu from './Menus/ArtistIndexFilterMenu';
|
import AuthorIndexFilterMenu from './Menus/AuthorIndexFilterMenu';
|
||||||
import ArtistIndexSortMenu from './Menus/ArtistIndexSortMenu';
|
import AuthorIndexSortMenu from './Menus/AuthorIndexSortMenu';
|
||||||
import ArtistIndexViewMenu from './Menus/ArtistIndexViewMenu';
|
import AuthorIndexViewMenu from './Menus/AuthorIndexViewMenu';
|
||||||
import styles from './ArtistIndex.css';
|
import styles from './AuthorIndex.css';
|
||||||
|
|
||||||
function getViewComponent(view) {
|
function getViewComponent(view) {
|
||||||
if (view === 'posters') {
|
if (view === 'posters') {
|
||||||
return ArtistIndexPostersConnector;
|
return AuthorIndexPostersConnector;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view === 'banners') {
|
if (view === 'banners') {
|
||||||
return ArtistIndexBannersConnector;
|
return AuthorIndexBannersConnector;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (view === 'overview') {
|
if (view === 'overview') {
|
||||||
return ArtistIndexOverviewsConnector;
|
return AuthorIndexOverviewsConnector;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ArtistIndexTableConnector;
|
return AuthorIndexTableConnector;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistIndex extends Component {
|
class AuthorIndex extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -184,13 +184,13 @@ class ArtistIndex extends Component {
|
|||||||
sortKey,
|
sortKey,
|
||||||
sortDirection,
|
sortDirection,
|
||||||
view,
|
view,
|
||||||
isRefreshingArtist,
|
isRefreshingAuthor,
|
||||||
isRssSyncExecuting,
|
isRssSyncExecuting,
|
||||||
onScroll,
|
onScroll,
|
||||||
onSortSelect,
|
onSortSelect,
|
||||||
onFilterSelect,
|
onFilterSelect,
|
||||||
onViewSelect,
|
onViewSelect,
|
||||||
onRefreshArtistPress,
|
onRefreshAuthorPress,
|
||||||
onRssSyncPress,
|
onRssSyncPress,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
@@ -206,7 +206,7 @@ class ArtistIndex extends Component {
|
|||||||
|
|
||||||
const ViewComponent = getViewComponent(view);
|
const ViewComponent = getViewComponent(view);
|
||||||
const isLoaded = !!(!error && isPopulated && items.length && scroller);
|
const isLoaded = !!(!error && isPopulated && items.length && scroller);
|
||||||
const hasNoArtist = !totalItems;
|
const hasNoAuthor = !totalItems;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent>
|
<PageContent>
|
||||||
@@ -216,15 +216,15 @@ class ArtistIndex extends Component {
|
|||||||
label="Update all"
|
label="Update all"
|
||||||
iconName={icons.REFRESH}
|
iconName={icons.REFRESH}
|
||||||
spinningName={icons.REFRESH}
|
spinningName={icons.REFRESH}
|
||||||
isSpinning={isRefreshingArtist}
|
isSpinning={isRefreshingAuthor}
|
||||||
onPress={onRefreshArtistPress}
|
onPress={onRefreshAuthorPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="RSS Sync"
|
label="RSS Sync"
|
||||||
iconName={icons.RSS}
|
iconName={icons.RSS}
|
||||||
isSpinning={isRssSyncExecuting}
|
isSpinning={isRssSyncExecuting}
|
||||||
isDisabled={hasNoArtist}
|
isDisabled={hasNoAuthor}
|
||||||
onPress={onRssSyncPress}
|
onPress={onRssSyncPress}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -239,7 +239,7 @@ class ArtistIndex extends Component {
|
|||||||
<TableOptionsModalWrapper
|
<TableOptionsModalWrapper
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
optionsComponent={ArtistIndexTableOptionsConnector}
|
optionsComponent={AuthorIndexTableOptionsConnector}
|
||||||
>
|
>
|
||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Options"
|
label="Options"
|
||||||
@@ -254,7 +254,7 @@ class ArtistIndex extends Component {
|
|||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Options"
|
label="Options"
|
||||||
iconName={icons.POSTER}
|
iconName={icons.POSTER}
|
||||||
isDisabled={hasNoArtist}
|
isDisabled={hasNoAuthor}
|
||||||
onPress={this.onPosterOptionsPress}
|
onPress={this.onPosterOptionsPress}
|
||||||
/> :
|
/> :
|
||||||
null
|
null
|
||||||
@@ -265,7 +265,7 @@ class ArtistIndex extends Component {
|
|||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Options"
|
label="Options"
|
||||||
iconName={icons.POSTER}
|
iconName={icons.POSTER}
|
||||||
isDisabled={hasNoArtist}
|
isDisabled={hasNoAuthor}
|
||||||
onPress={this.onBannerOptionsPress}
|
onPress={this.onBannerOptionsPress}
|
||||||
/> :
|
/> :
|
||||||
null
|
null
|
||||||
@@ -276,7 +276,7 @@ class ArtistIndex extends Component {
|
|||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label="Options"
|
label="Options"
|
||||||
iconName={icons.OVERVIEW}
|
iconName={icons.OVERVIEW}
|
||||||
isDisabled={hasNoArtist}
|
isDisabled={hasNoAuthor}
|
||||||
onPress={this.onOverviewOptionsPress}
|
onPress={this.onOverviewOptionsPress}
|
||||||
/> :
|
/> :
|
||||||
null
|
null
|
||||||
@@ -288,24 +288,24 @@ class ArtistIndex extends Component {
|
|||||||
<PageToolbarSeparator />
|
<PageToolbarSeparator />
|
||||||
}
|
}
|
||||||
|
|
||||||
<ArtistIndexViewMenu
|
<AuthorIndexViewMenu
|
||||||
view={view}
|
view={view}
|
||||||
isDisabled={hasNoArtist}
|
isDisabled={hasNoAuthor}
|
||||||
onViewSelect={onViewSelect}
|
onViewSelect={onViewSelect}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ArtistIndexSortMenu
|
<AuthorIndexSortMenu
|
||||||
sortKey={sortKey}
|
sortKey={sortKey}
|
||||||
sortDirection={sortDirection}
|
sortDirection={sortDirection}
|
||||||
isDisabled={hasNoArtist}
|
isDisabled={hasNoAuthor}
|
||||||
onSortSelect={onSortSelect}
|
onSortSelect={onSortSelect}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ArtistIndexFilterMenu
|
<AuthorIndexFilterMenu
|
||||||
selectedFilterKey={selectedFilterKey}
|
selectedFilterKey={selectedFilterKey}
|
||||||
filters={filters}
|
filters={filters}
|
||||||
customFilters={customFilters}
|
customFilters={customFilters}
|
||||||
isDisabled={hasNoArtist}
|
isDisabled={hasNoAuthor}
|
||||||
onFilterSelect={onFilterSelect}
|
onFilterSelect={onFilterSelect}
|
||||||
/>
|
/>
|
||||||
</PageToolbarSection>
|
</PageToolbarSection>
|
||||||
@@ -326,7 +326,7 @@ class ArtistIndex extends Component {
|
|||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div className={styles.errorMessage}>
|
<div className={styles.errorMessage}>
|
||||||
{getErrorMessage(error, 'Failed to load artist from API')}
|
{getErrorMessage(error, 'Failed to load author from API')}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,13 +343,13 @@ class ArtistIndex extends Component {
|
|||||||
{...otherProps}
|
{...otherProps}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ArtistIndexFooterConnector />
|
<AuthorIndexFooterConnector />
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!error && isPopulated && !items.length &&
|
!error && isPopulated && !items.length &&
|
||||||
<NoArtist totalItems={totalItems} />
|
<NoAuthor totalItems={totalItems} />
|
||||||
}
|
}
|
||||||
</PageContentBodyConnector>
|
</PageContentBodyConnector>
|
||||||
|
|
||||||
@@ -362,18 +362,18 @@ class ArtistIndex extends Component {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ArtistIndexPosterOptionsModal
|
<AuthorIndexPosterOptionsModal
|
||||||
isOpen={isPosterOptionsModalOpen}
|
isOpen={isPosterOptionsModalOpen}
|
||||||
onModalClose={this.onPosterOptionsModalClose}
|
onModalClose={this.onPosterOptionsModalClose}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ArtistIndexBannerOptionsModal
|
<AuthorIndexBannerOptionsModal
|
||||||
isOpen={isBannerOptionsModalOpen}
|
isOpen={isBannerOptionsModalOpen}
|
||||||
onModalClose={this.onBannerOptionsModalClose}
|
onModalClose={this.onBannerOptionsModalClose}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ArtistIndexOverviewOptionsModal
|
<AuthorIndexOverviewOptionsModal
|
||||||
isOpen={isOverviewOptionsModalOpen}
|
isOpen={isOverviewOptionsModalOpen}
|
||||||
onModalClose={this.onOverviewOptionsModalClose}
|
onModalClose={this.onOverviewOptionsModalClose}
|
||||||
|
|
||||||
@@ -383,7 +383,7 @@ class ArtistIndex extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistIndex.propTypes = {
|
AuthorIndex.propTypes = {
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
@@ -396,15 +396,15 @@ ArtistIndex.propTypes = {
|
|||||||
sortKey: PropTypes.string,
|
sortKey: PropTypes.string,
|
||||||
sortDirection: PropTypes.oneOf(sortDirections.all),
|
sortDirection: PropTypes.oneOf(sortDirections.all),
|
||||||
view: PropTypes.string.isRequired,
|
view: PropTypes.string.isRequired,
|
||||||
isRefreshingArtist: PropTypes.bool.isRequired,
|
isRefreshingAuthor: PropTypes.bool.isRequired,
|
||||||
isRssSyncExecuting: PropTypes.bool.isRequired,
|
isRssSyncExecuting: PropTypes.bool.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
onSortSelect: PropTypes.func.isRequired,
|
onSortSelect: PropTypes.func.isRequired,
|
||||||
onFilterSelect: PropTypes.func.isRequired,
|
onFilterSelect: PropTypes.func.isRequired,
|
||||||
onViewSelect: PropTypes.func.isRequired,
|
onViewSelect: PropTypes.func.isRequired,
|
||||||
onRefreshArtistPress: PropTypes.func.isRequired,
|
onRefreshAuthorPress: PropTypes.func.isRequired,
|
||||||
onRssSyncPress: PropTypes.func.isRequired,
|
onRssSyncPress: PropTypes.func.isRequired,
|
||||||
onScroll: PropTypes.func.isRequired
|
onScroll: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistIndex;
|
export default AuthorIndex;
|
||||||
@@ -3,31 +3,32 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createArtistClientSideCollectionItemsSelector from 'Store/Selectors/createArtistClientSideCollectionItemsSelector';
|
import createAuthorClientSideCollectionItemsSelector
|
||||||
|
from 'Store/Selectors/createAuthorClientSideCollectionItemsSelector';
|
||||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||||
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
|
||||||
import scrollPositions from 'Store/scrollPositions';
|
import scrollPositions from 'Store/scrollPositions';
|
||||||
import { setArtistSort, setArtistFilter, setArtistView, setArtistTableOption } from 'Store/Actions/artistIndexActions';
|
import { setAuthorFilter, setAuthorSort, setAuthorTableOption, setAuthorView } from 'Store/Actions/authorIndexActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
import withScrollPosition from 'Components/withScrollPosition';
|
import withScrollPosition from 'Components/withScrollPosition';
|
||||||
import ArtistIndex from './ArtistIndex';
|
import AuthorIndex from './AuthorIndex';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistClientSideCollectionItemsSelector('artistIndex'),
|
createAuthorClientSideCollectionItemsSelector('authorIndex'),
|
||||||
createCommandExecutingSelector(commandNames.REFRESH_ARTIST),
|
createCommandExecutingSelector(commandNames.REFRESH_AUTHOR),
|
||||||
createCommandExecutingSelector(commandNames.RSS_SYNC),
|
createCommandExecutingSelector(commandNames.RSS_SYNC),
|
||||||
createDimensionsSelector(),
|
createDimensionsSelector(),
|
||||||
(
|
(
|
||||||
artist,
|
author,
|
||||||
isRefreshingArtist,
|
isRefreshingAuthor,
|
||||||
isRssSyncExecuting,
|
isRssSyncExecuting,
|
||||||
dimensionsState
|
dimensionsState
|
||||||
) => {
|
) => {
|
||||||
return {
|
return {
|
||||||
...artist,
|
...author,
|
||||||
isRefreshingArtist,
|
isRefreshingAuthor,
|
||||||
isRssSyncExecuting,
|
isRssSyncExecuting,
|
||||||
isSmallScreen: dimensionsState.isSmallScreen
|
isSmallScreen: dimensionsState.isSmallScreen
|
||||||
};
|
};
|
||||||
@@ -38,24 +39,24 @@ function createMapStateToProps() {
|
|||||||
function createMapDispatchToProps(dispatch, props) {
|
function createMapDispatchToProps(dispatch, props) {
|
||||||
return {
|
return {
|
||||||
onTableOptionChange(payload) {
|
onTableOptionChange(payload) {
|
||||||
dispatch(setArtistTableOption(payload));
|
dispatch(setAuthorTableOption(payload));
|
||||||
},
|
},
|
||||||
|
|
||||||
onSortSelect(sortKey) {
|
onSortSelect(sortKey) {
|
||||||
dispatch(setArtistSort({ sortKey }));
|
dispatch(setAuthorSort({ sortKey }));
|
||||||
},
|
},
|
||||||
|
|
||||||
onFilterSelect(selectedFilterKey) {
|
onFilterSelect(selectedFilterKey) {
|
||||||
dispatch(setArtistFilter({ selectedFilterKey }));
|
dispatch(setAuthorFilter({ selectedFilterKey }));
|
||||||
},
|
},
|
||||||
|
|
||||||
dispatchSetArtistView(view) {
|
dispatchSetAuthorView(view) {
|
||||||
dispatch(setArtistView({ view }));
|
dispatch(setAuthorView({ view }));
|
||||||
},
|
},
|
||||||
|
|
||||||
onRefreshArtistPress() {
|
onRefreshAuthorPress() {
|
||||||
dispatch(executeCommand({
|
dispatch(executeCommand({
|
||||||
name: commandNames.REFRESH_ARTIST
|
name: commandNames.REFRESH_AUTHOR
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -67,17 +68,17 @@ function createMapDispatchToProps(dispatch, props) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArtistIndexConnector extends Component {
|
class AuthorIndexConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onViewSelect = (view) => {
|
onViewSelect = (view) => {
|
||||||
this.props.dispatchSetArtistView(view);
|
this.props.dispatchSetAuthorView(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
onScroll = ({ scrollTop }) => {
|
onScroll = ({ scrollTop }) => {
|
||||||
scrollPositions.artistIndex = scrollTop;
|
scrollPositions.authorIndex = scrollTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -85,7 +86,7 @@ class ArtistIndexConnector extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ArtistIndex
|
<AuthorIndex
|
||||||
{...this.props}
|
{...this.props}
|
||||||
onViewSelect={this.onViewSelect}
|
onViewSelect={this.onViewSelect}
|
||||||
onScroll={this.onScroll}
|
onScroll={this.onScroll}
|
||||||
@@ -94,13 +95,13 @@ class ArtistIndexConnector extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistIndexConnector.propTypes = {
|
AuthorIndexConnector.propTypes = {
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired,
|
||||||
view: PropTypes.string.isRequired,
|
view: PropTypes.string.isRequired,
|
||||||
dispatchSetArtistView: PropTypes.func.isRequired
|
dispatchSetAuthorView: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default withScrollPosition(
|
export default withScrollPosition(
|
||||||
connect(createMapStateToProps, createMapDispatchToProps)(ArtistIndexConnector),
|
connect(createMapStateToProps, createMapDispatchToProps)(AuthorIndexConnector),
|
||||||
'artistIndex'
|
'authorIndex'
|
||||||
);
|
);
|
||||||
@@ -1,24 +1,24 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { setArtistFilter } from 'Store/Actions/artistIndexActions';
|
import { setAuthorFilter } from 'Store/Actions/authorIndexActions';
|
||||||
import FilterModal from 'Components/Filter/FilterModal';
|
import FilterModal from 'Components/Filter/FilterModal';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.artist.items,
|
(state) => state.authors.items,
|
||||||
(state) => state.artistIndex.filterBuilderProps,
|
(state) => state.authorIndex.filterBuilderProps,
|
||||||
(sectionItems, filterBuilderProps) => {
|
(sectionItems, filterBuilderProps) => {
|
||||||
return {
|
return {
|
||||||
sectionItems,
|
sectionItems,
|
||||||
filterBuilderProps,
|
filterBuilderProps,
|
||||||
customFilterType: 'artistIndex'
|
customFilterType: 'authorIndex'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
dispatchSetFilter: setArtistFilter
|
dispatchSetFilter: setAuthorFilter
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(FilterModal);
|
export default connect(createMapStateToProps, mapDispatchToProps)(FilterModal);
|
||||||
@@ -5,34 +5,34 @@ import formatBytes from 'Utilities/Number/formatBytes';
|
|||||||
import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
|
import { ColorImpairedConsumer } from 'App/ColorImpairedContext';
|
||||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||||
import styles from './ArtistIndexFooter.css';
|
import styles from './AuthorIndexFooter.css';
|
||||||
|
|
||||||
class ArtistIndexFooter extends PureComponent {
|
class AuthorIndexFooter extends PureComponent {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { artist } = this.props;
|
const { author } = this.props;
|
||||||
const count = artist.length;
|
const count = author.length;
|
||||||
let tracks = 0;
|
let books = 0;
|
||||||
let trackFiles = 0;
|
let bookFiles = 0;
|
||||||
let ended = 0;
|
let ended = 0;
|
||||||
let continuing = 0;
|
let continuing = 0;
|
||||||
let monitored = 0;
|
let monitored = 0;
|
||||||
let totalFileSize = 0;
|
let totalFileSize = 0;
|
||||||
|
|
||||||
artist.forEach((s) => {
|
author.forEach((s) => {
|
||||||
const { statistics = {} } = s;
|
const { statistics = {} } = s;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
trackCount = 0,
|
bookCount = 0,
|
||||||
trackFileCount = 0,
|
bookFileCount = 0,
|
||||||
sizeOnDisk = 0
|
sizeOnDisk = 0
|
||||||
} = statistics;
|
} = statistics;
|
||||||
|
|
||||||
tracks += trackCount;
|
books += bookCount;
|
||||||
trackFiles += trackFileCount;
|
bookFiles += bookFileCount;
|
||||||
|
|
||||||
if (s.status === 'ended') {
|
if (s.status === 'ended') {
|
||||||
ended++;
|
ended++;
|
||||||
@@ -127,12 +127,12 @@ class ArtistIndexFooter extends PureComponent {
|
|||||||
<DescriptionList>
|
<DescriptionList>
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
title="Books"
|
title="Books"
|
||||||
data={tracks}
|
data={books}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
title="Files"
|
title="Files"
|
||||||
data={trackFiles}
|
data={bookFiles}
|
||||||
/>
|
/>
|
||||||
</DescriptionList>
|
</DescriptionList>
|
||||||
|
|
||||||
@@ -151,8 +151,8 @@ class ArtistIndexFooter extends PureComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistIndexFooter.propTypes = {
|
AuthorIndexFooter.propTypes = {
|
||||||
artist: PropTypes.arrayOf(PropTypes.object).isRequired
|
author: PropTypes.arrayOf(PropTypes.object).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ArtistIndexFooter;
|
export default AuthorIndexFooter;
|
||||||
@@ -2,13 +2,13 @@ import { connect } from 'react-redux';
|
|||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createDeepEqualSelector from 'Store/Selectors/createDeepEqualSelector';
|
import createDeepEqualSelector from 'Store/Selectors/createDeepEqualSelector';
|
||||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||||
import ArtistIndexFooter from './ArtistIndexFooter';
|
import AuthorIndexFooter from './AuthorIndexFooter';
|
||||||
|
|
||||||
function createUnoptimizedSelector() {
|
function createUnoptimizedSelector() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createClientSideCollectionSelector('artist', 'artistIndex'),
|
createClientSideCollectionSelector('authors', 'authorIndex'),
|
||||||
(artist) => {
|
(authors) => {
|
||||||
return artist.items.map((s) => {
|
return authors.items.map((s) => {
|
||||||
const {
|
const {
|
||||||
monitored,
|
monitored,
|
||||||
status,
|
status,
|
||||||
@@ -25,22 +25,22 @@ function createUnoptimizedSelector() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createArtistSelector() {
|
function createAuthorSelector() {
|
||||||
return createDeepEqualSelector(
|
return createDeepEqualSelector(
|
||||||
createUnoptimizedSelector(),
|
createUnoptimizedSelector(),
|
||||||
(artist) => artist
|
(author) => author
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
(artist) => {
|
(author) => {
|
||||||
return {
|
return {
|
||||||
artist
|
author
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(createMapStateToProps)(ArtistIndexFooter);
|
export default connect(createMapStateToProps)(AuthorIndexFooter);
|
||||||
@@ -4,28 +4,28 @@ import PropTypes from 'prop-types';
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
import createAuthorSelector from 'Store/Selectors/createAuthorSelector';
|
||||||
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
|
import createExecutingCommandsSelector from 'Store/Selectors/createExecutingCommandsSelector';
|
||||||
import createArtistQualityProfileSelector from 'Store/Selectors/createArtistQualityProfileSelector';
|
import createAuthorQualityProfileSelector from 'Store/Selectors/createAuthorQualityProfileSelector';
|
||||||
import createArtistMetadataProfileSelector from 'Store/Selectors/createArtistMetadataProfileSelector';
|
import createAuthorMetadataProfileSelector from 'Store/Selectors/createAuthorMetadataProfileSelector';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import * as commandNames from 'Commands/commandNames';
|
import * as commandNames from 'Commands/commandNames';
|
||||||
|
|
||||||
function selectShowSearchAction() {
|
function selectShowSearchAction() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.artistIndex,
|
(state) => state.authorIndex,
|
||||||
(artistIndex) => {
|
(authorIndex) => {
|
||||||
const view = artistIndex.view;
|
const view = authorIndex.view;
|
||||||
|
|
||||||
switch (view) {
|
switch (view) {
|
||||||
case 'posters':
|
case 'posters':
|
||||||
return artistIndex.posterOptions.showSearchAction;
|
return authorIndex.posterOptions.showSearchAction;
|
||||||
case 'banners':
|
case 'banners':
|
||||||
return artistIndex.bannerOptions.showSearchAction;
|
return authorIndex.bannerOptions.showSearchAction;
|
||||||
case 'overview':
|
case 'overview':
|
||||||
return artistIndex.overviewOptions.showSearchAction;
|
return authorIndex.overviewOptions.showSearchAction;
|
||||||
default:
|
default:
|
||||||
return artistIndex.tableOptions.showSearchAction;
|
return authorIndex.tableOptions.showSearchAction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -33,52 +33,52 @@ function selectShowSearchAction() {
|
|||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
createArtistSelector(),
|
createAuthorSelector(),
|
||||||
createArtistQualityProfileSelector(),
|
createAuthorQualityProfileSelector(),
|
||||||
createArtistMetadataProfileSelector(),
|
createAuthorMetadataProfileSelector(),
|
||||||
selectShowSearchAction(),
|
selectShowSearchAction(),
|
||||||
createExecutingCommandsSelector(),
|
createExecutingCommandsSelector(),
|
||||||
(
|
(
|
||||||
artist,
|
author,
|
||||||
qualityProfile,
|
qualityProfile,
|
||||||
metadataProfile,
|
metadataProfile,
|
||||||
showSearchAction,
|
showSearchAction,
|
||||||
executingCommands
|
executingCommands
|
||||||
) => {
|
) => {
|
||||||
|
|
||||||
// If an artist is deleted this selector may fire before the parent
|
// If an author is deleted this selector may fire before the parent
|
||||||
// selectors, which will result in an undefined artist, if that happens
|
// selectors, which will result in an undefined author, if that happens
|
||||||
// we want to return early here and again in the render function to avoid
|
// we want to return early here and again in the render function to avoid
|
||||||
// trying to show an artist that has no information available.
|
// trying to show an author that has no information available.
|
||||||
|
|
||||||
if (!artist) {
|
if (!author) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const isRefreshingArtist = executingCommands.some((command) => {
|
const isRefreshingAuthor = executingCommands.some((command) => {
|
||||||
return (
|
return (
|
||||||
command.name === commandNames.REFRESH_ARTIST &&
|
command.name === commandNames.REFRESH_AUTHOR &&
|
||||||
command.body.authorId === artist.id
|
command.body.authorId === author.id
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const isSearchingArtist = executingCommands.some((command) => {
|
const isSearchingAuthor = executingCommands.some((command) => {
|
||||||
return (
|
return (
|
||||||
command.name === commandNames.ARTIST_SEARCH &&
|
command.name === commandNames.AUTHOR_SEARCH &&
|
||||||
command.body.authorId === artist.id
|
command.body.authorId === author.id
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const latestAlbum = _.maxBy(artist.albums, (album) => album.releaseDate);
|
const latestBook = _.maxBy(author.books, (book) => book.releaseDate);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...artist,
|
...author,
|
||||||
qualityProfile,
|
qualityProfile,
|
||||||
metadataProfile,
|
metadataProfile,
|
||||||
latestAlbum,
|
latestBook,
|
||||||
showSearchAction,
|
showSearchAction,
|
||||||
isRefreshingArtist,
|
isRefreshingAuthor,
|
||||||
isSearchingArtist
|
isSearchingAuthor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -88,21 +88,21 @@ const mapDispatchToProps = {
|
|||||||
dispatchExecuteCommand: executeCommand
|
dispatchExecuteCommand: executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArtistIndexItemConnector extends Component {
|
class AuthorIndexItemConnector extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onRefreshArtistPress = () => {
|
onRefreshAuthorPress = () => {
|
||||||
this.props.dispatchExecuteCommand({
|
this.props.dispatchExecuteCommand({
|
||||||
name: commandNames.REFRESH_ARTIST,
|
name: commandNames.REFRESH_AUTHOR,
|
||||||
authorId: this.props.id
|
authorId: this.props.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchPress = () => {
|
onSearchPress = () => {
|
||||||
this.props.dispatchExecuteCommand({
|
this.props.dispatchExecuteCommand({
|
||||||
name: commandNames.ARTIST_SEARCH,
|
name: commandNames.AUTHOR_SEARCH,
|
||||||
authorId: this.props.id
|
authorId: this.props.id
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -125,17 +125,17 @@ class ArtistIndexItemConnector extends Component {
|
|||||||
<ItemComponent
|
<ItemComponent
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
id={id}
|
id={id}
|
||||||
onRefreshArtistPress={this.onRefreshArtistPress}
|
onRefreshAuthorPress={this.onRefreshAuthorPress}
|
||||||
onSearchPress={this.onSearchPress}
|
onSearchPress={this.onSearchPress}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArtistIndexItemConnector.propTypes = {
|
AuthorIndexItemConnector.propTypes = {
|
||||||
id: PropTypes.number,
|
id: PropTypes.number,
|
||||||
component: PropTypes.elementType.isRequired,
|
component: PropTypes.elementType.isRequired,
|
||||||
dispatchExecuteCommand: PropTypes.func.isRequired
|
dispatchExecuteCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(ArtistIndexItemConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AuthorIndexItemConnector);
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user