mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-21 22:04:31 -04:00
New: Readarr 0.1
This commit is contained in:
@@ -1,34 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import TrackFileEditorModalContentConnector from './TrackFileEditorModalContentConnector';
|
||||
|
||||
function TrackFileEditorModal(props) {
|
||||
const {
|
||||
isOpen,
|
||||
onModalClose,
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onModalClose={onModalClose}
|
||||
>
|
||||
{
|
||||
isOpen &&
|
||||
<TrackFileEditorModalContentConnector
|
||||
{...otherProps}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
TrackFileEditorModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default TrackFileEditorModal;
|
||||
@@ -1,6 +1,5 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import padNumber from 'Utilities/Number/padNumber';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
@@ -9,7 +8,6 @@ import TrackQuality from 'Album/TrackQuality';
|
||||
function TrackFileEditorRow(props) {
|
||||
const {
|
||||
id,
|
||||
trackNumber,
|
||||
path,
|
||||
quality,
|
||||
isSelected,
|
||||
@@ -23,11 +21,6 @@ function TrackFileEditorRow(props) {
|
||||
isSelected={isSelected}
|
||||
onSelectedChange={onSelectedChange}
|
||||
/>
|
||||
|
||||
<TableRowCell>
|
||||
{padNumber(trackNumber, 2)}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell>
|
||||
{path}
|
||||
</TableRowCell>
|
||||
@@ -43,7 +36,6 @@ function TrackFileEditorRow(props) {
|
||||
|
||||
TrackFileEditorRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
trackNumber: PropTypes.string.isRequired,
|
||||
path: PropTypes.string.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
isSelected: PropTypes.bool,
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import TrackFileEditorTableContentConnector from './TrackFileEditorTableContentConnector';
|
||||
|
||||
function TrackFileEditorTable(props) {
|
||||
const {
|
||||
...otherProps
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<TrackFileEditorTableContentConnector
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default TrackFileEditorTable;
|
||||
+69
-95
@@ -8,25 +8,15 @@ import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import Button from 'Components/Link/Button';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import SelectInput from 'Components/Form/SelectInput';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import TrackFileEditorRow from './TrackFileEditorRow';
|
||||
import styles from './TrackFileEditorModalContent.css';
|
||||
import styles from './TrackFileEditorTableContent.css';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'trackNumber',
|
||||
label: 'Track',
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'path',
|
||||
label: 'Path',
|
||||
@@ -39,7 +29,7 @@ const columns = [
|
||||
}
|
||||
];
|
||||
|
||||
class TrackFileEditorModalContent extends Component {
|
||||
class TrackFileEditorTableContent extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
@@ -127,8 +117,7 @@ class TrackFileEditorModalContent extends Component {
|
||||
isPopulated,
|
||||
error,
|
||||
items,
|
||||
qualities,
|
||||
onModalClose
|
||||
qualities
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
@@ -150,88 +139,74 @@ class TrackFileEditorModalContent extends Component {
|
||||
const hasSelectedFiles = this.getSelectedIds().length > 0;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>
|
||||
Manage Tracks
|
||||
</ModalHeader>
|
||||
<>
|
||||
{
|
||||
isFetching && !isPopulated ?
|
||||
<LoadingIndicator /> :
|
||||
null
|
||||
}
|
||||
|
||||
<ModalBody>
|
||||
{
|
||||
isFetching && !isPopulated ?
|
||||
<LoadingIndicator /> :
|
||||
null
|
||||
}
|
||||
{
|
||||
!isFetching && error ?
|
||||
<div>{error}</div> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && error ?
|
||||
<div>{error}</div> :
|
||||
null
|
||||
}
|
||||
{
|
||||
isPopulated && !items.length ?
|
||||
<div>
|
||||
No track files to manage.
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && !items.length ?
|
||||
<div>
|
||||
No track files to manage.
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && items.length ?
|
||||
<Table
|
||||
columns={columns}
|
||||
selectAll={true}
|
||||
allSelected={allSelected}
|
||||
allUnselected={allUnselected}
|
||||
onSelectAllChange={this.onSelectAllChange}
|
||||
>
|
||||
<TableBody>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<TrackFileEditorRow
|
||||
key={item.id}
|
||||
isSelected={selectedState[item.id]}
|
||||
{...item}
|
||||
onSelectedChange={this.onSelectedChange}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</TableBody>
|
||||
</Table> :
|
||||
null
|
||||
}
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<div className={styles.actions}>
|
||||
<SpinnerButton
|
||||
kind={kinds.DANGER}
|
||||
isSpinning={isDeleting}
|
||||
isDisabled={!hasSelectedFiles}
|
||||
onPress={this.onDeletePress}
|
||||
{
|
||||
isPopulated && items.length ?
|
||||
<Table
|
||||
columns={columns}
|
||||
selectAll={true}
|
||||
allSelected={allSelected}
|
||||
allUnselected={allUnselected}
|
||||
onSelectAllChange={this.onSelectAllChange}
|
||||
>
|
||||
Delete
|
||||
</SpinnerButton>
|
||||
<TableBody>
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<TrackFileEditorRow
|
||||
key={item.id}
|
||||
isSelected={selectedState[item.id]}
|
||||
{...item}
|
||||
onSelectedChange={this.onSelectedChange}
|
||||
/>
|
||||
);
|
||||
})
|
||||
}
|
||||
</TableBody>
|
||||
</Table> :
|
||||
null
|
||||
}
|
||||
|
||||
<div className={styles.selectInput}>
|
||||
<SelectInput
|
||||
name="quality"
|
||||
value="selectQuality"
|
||||
values={qualityOptions}
|
||||
isDisabled={!hasSelectedFiles}
|
||||
onChange={this.onQualityChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Button
|
||||
onPress={onModalClose}
|
||||
<div className={styles.actions}>
|
||||
<SpinnerButton
|
||||
kind={kinds.DANGER}
|
||||
isSpinning={isDeleting}
|
||||
isDisabled={!hasSelectedFiles}
|
||||
onPress={this.onDeletePress}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
Delete
|
||||
</SpinnerButton>
|
||||
|
||||
<div className={styles.selectInput}>
|
||||
<SelectInput
|
||||
name="quality"
|
||||
value="selectQuality"
|
||||
values={qualityOptions}
|
||||
isDisabled={!hasSelectedFiles}
|
||||
onChange={this.onQualityChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isConfirmDeleteModalOpen}
|
||||
@@ -242,12 +217,12 @@ class TrackFileEditorModalContent extends Component {
|
||||
onConfirm={this.onConfirmDelete}
|
||||
onCancel={this.onConfirmDeleteModalClose}
|
||||
/>
|
||||
</ModalContent>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TrackFileEditorModalContent.propTypes = {
|
||||
TrackFileEditorTableContent.propTypes = {
|
||||
isDeleting: PropTypes.bool.isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
@@ -255,8 +230,7 @@ TrackFileEditorModalContent.propTypes = {
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
qualities: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onDeletePress: PropTypes.func.isRequired,
|
||||
onQualityChange: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
onQualityChange: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default TrackFileEditorModalContent;
|
||||
export default TrackFileEditorTableContent;
|
||||
+10
-45
@@ -9,7 +9,7 @@ import createArtistSelector from 'Store/Selectors/createArtistSelector';
|
||||
import { deleteTrackFiles, updateTrackFiles } from 'Store/Actions/trackFileActions';
|
||||
import { fetchTracks, clearTracks } from 'Store/Actions/trackActions';
|
||||
import { fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
||||
import TrackFileEditorModalContent from './TrackFileEditorModalContent';
|
||||
import TrackFileEditorTableContent from './TrackFileEditorTableContent';
|
||||
|
||||
function createSchemaSelector() {
|
||||
return createSelector(
|
||||
@@ -35,45 +35,19 @@ function createSchemaSelector() {
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state, { albumId }) => albumId,
|
||||
(state) => state.tracks,
|
||||
(state, { bookId }) => bookId,
|
||||
(state) => state.trackFiles,
|
||||
createSchemaSelector(),
|
||||
createArtistSelector(),
|
||||
(
|
||||
albumId,
|
||||
tracks,
|
||||
bookId,
|
||||
trackFiles,
|
||||
schema,
|
||||
artist
|
||||
) => {
|
||||
const filtered = _.filter(tracks.items, (track) => {
|
||||
if (albumId >= 0 && track.albumId !== albumId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!track.trackFileId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return _.some(trackFiles.items, { id: track.trackFileId });
|
||||
});
|
||||
|
||||
const sorted = _.orderBy(filtered, ['albumId', 'absoluteTrackNumber'], ['desc', 'asc']);
|
||||
|
||||
const items = _.map(sorted, (track) => {
|
||||
const trackFile = _.find(trackFiles.items, { id: track.trackFileId });
|
||||
|
||||
return {
|
||||
path: trackFile.path,
|
||||
quality: trackFile.quality,
|
||||
...track
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
...schema,
|
||||
items,
|
||||
items: trackFiles.items,
|
||||
artistType: artist.artistType,
|
||||
isDeleting: trackFiles.isDeleting,
|
||||
isSaving: trackFiles.isSaving
|
||||
@@ -106,24 +80,15 @@ function createMapDispatchToProps(dispatch, props) {
|
||||
};
|
||||
}
|
||||
|
||||
class TrackFileEditorModalContentConnector extends Component {
|
||||
class TrackFileEditorTableContentConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const artistId = this.props.artistId;
|
||||
const albumId = this.props.albumId;
|
||||
|
||||
this.props.dispatchFetchTracks({ artistId, albumId });
|
||||
|
||||
this.props.dispatchFetchQualityProfileSchema();
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.dispatchClearTracks();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
@@ -152,7 +117,7 @@ class TrackFileEditorModalContentConnector extends Component {
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<TrackFileEditorModalContent
|
||||
<TrackFileEditorTableContent
|
||||
{...otherProps}
|
||||
onQualityChange={this.onQualityChange}
|
||||
/>
|
||||
@@ -160,9 +125,9 @@ class TrackFileEditorModalContentConnector extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
TrackFileEditorModalContentConnector.propTypes = {
|
||||
artistId: PropTypes.number.isRequired,
|
||||
albumId: PropTypes.number,
|
||||
TrackFileEditorTableContentConnector.propTypes = {
|
||||
authorId: PropTypes.number.isRequired,
|
||||
bookId: PropTypes.number,
|
||||
qualities: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
dispatchFetchTracks: PropTypes.func.isRequired,
|
||||
dispatchClearTracks: PropTypes.func.isRequired,
|
||||
@@ -170,4 +135,4 @@ TrackFileEditorModalContentConnector.propTypes = {
|
||||
dispatchUpdateTrackFiles: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(TrackFileEditorModalContentConnector);
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(TrackFileEditorTableContentConnector);
|
||||
@@ -135,7 +135,7 @@ function FileDetails(props) {
|
||||
{
|
||||
audioTags.artistMBId !== undefined &&
|
||||
<Link
|
||||
to={`https://musicbrainz.org/artist/${audioTags.artistMBId}`}
|
||||
to={`https://musicbrainz.org/author/${audioTags.artistMBId}`}
|
||||
>
|
||||
<DescriptionListItem
|
||||
title="MusicBrainz Artist ID"
|
||||
|
||||
Reference in New Issue
Block a user