mirror of https://github.com/lidarr/Lidarr
New: Album group improvements on Artist Details page
This commit is contained in:
parent
7e10d6b59c
commit
4b367d3129
|
@ -0,0 +1,11 @@
|
|||
.title {
|
||||
composes: title from '~Components/DescriptionList/DescriptionListItemTitle.css';
|
||||
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
.description {
|
||||
composes: title from '~Components/DescriptionList/DescriptionListItemDescription.css';
|
||||
|
||||
margin-left: 110px;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import DescriptionList from 'Components/DescriptionList/DescriptionList';
|
||||
import DescriptionListItem from 'Components/DescriptionList/DescriptionListItem';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import styles from './AlbumGroupInfo.css';
|
||||
|
||||
function AlbumGroupInfo(props) {
|
||||
const {
|
||||
totalAlbumCount,
|
||||
monitoredAlbumCount,
|
||||
trackFileCount,
|
||||
sizeOnDisk
|
||||
} = props;
|
||||
|
||||
return (
|
||||
<DescriptionList>
|
||||
<DescriptionListItem
|
||||
titleClassName={styles.title}
|
||||
descriptionClassName={styles.description}
|
||||
title="Total"
|
||||
data={totalAlbumCount}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
titleClassName={styles.title}
|
||||
descriptionClassName={styles.description}
|
||||
title="Monitored"
|
||||
data={monitoredAlbumCount}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
titleClassName={styles.title}
|
||||
descriptionClassName={styles.description}
|
||||
title="Track Files"
|
||||
data={trackFileCount}
|
||||
/>
|
||||
|
||||
<DescriptionListItem
|
||||
titleClassName={styles.title}
|
||||
descriptionClassName={styles.description}
|
||||
title="Size on Disk"
|
||||
data={formatBytes(sizeOnDisk)}
|
||||
/>
|
||||
</DescriptionList>
|
||||
);
|
||||
}
|
||||
|
||||
AlbumGroupInfo.propTypes = {
|
||||
totalAlbumCount: PropTypes.number.isRequired,
|
||||
monitoredAlbumCount: PropTypes.number.isRequired,
|
||||
trackFileCount: PropTypes.number.isRequired,
|
||||
sizeOnDisk: PropTypes.number.isRequired
|
||||
};
|
||||
|
||||
export default AlbumGroupInfo;
|
|
@ -15,11 +15,10 @@
|
|||
align-items: center;
|
||||
width: 100%;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.albumTypeLabel {
|
||||
margin-right: 5px;
|
||||
margin-right: 10px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
@ -29,10 +28,16 @@
|
|||
font-size: 18px;
|
||||
}
|
||||
|
||||
.episodeCountTooltip {
|
||||
.albumCountTooltip {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.sizeOnDisk {
|
||||
margin-left: 10px;
|
||||
color: #777;
|
||||
font-size: $defaultFontSize;
|
||||
}
|
||||
|
||||
.expandButton {
|
||||
composes: link from '~Components/Link/Link.css';
|
||||
|
||||
|
@ -44,7 +49,7 @@
|
|||
.left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex: 0 1 300px;
|
||||
flex: 0 1 350px;
|
||||
}
|
||||
|
||||
.left,
|
||||
|
@ -103,7 +108,7 @@
|
|||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -12px;
|
||||
margin-left: -15px;
|
||||
margin-left: -12px;
|
||||
}
|
||||
|
||||
.noAlbums {
|
||||
|
@ -122,4 +127,8 @@
|
|||
position: static;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.sizeOnDisk {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,18 +2,70 @@ import _ from 'lodash';
|
|||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import Label from 'Components/Label';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import Link from 'Components/Link/Link';
|
||||
import MonitorToggleButton from 'Components/MonitorToggleButton';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import { icons, sortDirections } from 'Helpers/Props';
|
||||
import Popover from 'Components/Tooltip/Popover';
|
||||
import { icons, kinds, sizes, sortDirections, tooltipPositions } from 'Helpers/Props';
|
||||
import OrganizePreviewModalConnector from 'Organize/OrganizePreviewModalConnector';
|
||||
import TrackFileEditorModal from 'TrackFile/Editor/TrackFileEditorModal';
|
||||
import isBefore from 'Utilities/Date/isBefore';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import getToggledRange from 'Utilities/Table/getToggledRange';
|
||||
import AlbumGroupInfo from './AlbumGroupInfo';
|
||||
import AlbumRowConnector from './AlbumRowConnector';
|
||||
import styles from './ArtistDetailsSeason.css';
|
||||
|
||||
function getAlbumTypeStatistics(albums) {
|
||||
let albumCount = 0;
|
||||
let trackFileCount = 0;
|
||||
let totalAlbumCount = 0;
|
||||
let monitoredAlbumCount = 0;
|
||||
let hasMonitoredAlbums = false;
|
||||
let sizeOnDisk = 0;
|
||||
|
||||
albums.forEach((album) => {
|
||||
sizeOnDisk = sizeOnDisk + album.statistics.sizeOnDisk;
|
||||
trackFileCount = trackFileCount + album.statistics.trackFileCount;
|
||||
|
||||
if (album.statistics.trackFileCount === album.statistics.totalTrackCount || (album.monitored && isBefore(album.airDateUtc))) {
|
||||
albumCount++;
|
||||
}
|
||||
|
||||
if (album.monitored) {
|
||||
monitoredAlbumCount++;
|
||||
hasMonitoredAlbums = true;
|
||||
}
|
||||
|
||||
totalAlbumCount++;
|
||||
});
|
||||
|
||||
return {
|
||||
albumCount,
|
||||
totalAlbumCount,
|
||||
trackFileCount,
|
||||
monitoredAlbumCount,
|
||||
sizeOnDisk,
|
||||
hasMonitoredAlbums
|
||||
};
|
||||
}
|
||||
|
||||
function getAlbumCountKind(monitored, albumCount, monitoredAlbumCount) {
|
||||
if (albumCount === monitoredAlbumCount && monitoredAlbumCount > 0) {
|
||||
return kinds.SUCCESS;
|
||||
}
|
||||
|
||||
if (!monitored) {
|
||||
return kinds.WARNING;
|
||||
}
|
||||
|
||||
return kinds.DANGER;
|
||||
}
|
||||
|
||||
class ArtistDetailsSeason extends Component {
|
||||
|
||||
//
|
||||
|
@ -108,7 +160,13 @@ class ArtistDetailsSeason extends Component {
|
|||
|
||||
this.setState({ lastToggledAlbum: albumId });
|
||||
|
||||
this.props.onMonitorAlbumPress(_.uniq(albumIds), monitored);
|
||||
this.props.onMonitorAlbumsPress(_.uniq(albumIds), monitored);
|
||||
};
|
||||
|
||||
onMonitorAlbumsPress = (monitored, { shiftKey }) => {
|
||||
const albumIds = this.props.items.map((a) => a.id);
|
||||
|
||||
this.props.onMonitorAlbumsPress(_.uniq(albumIds), monitored);
|
||||
};
|
||||
|
||||
//
|
||||
|
@ -120,7 +178,9 @@ class ArtistDetailsSeason extends Component {
|
|||
label,
|
||||
items,
|
||||
columns,
|
||||
isSaving,
|
||||
isExpanded,
|
||||
artistMonitored,
|
||||
sortKey,
|
||||
sortDirection,
|
||||
onSortPress,
|
||||
|
@ -128,6 +188,15 @@ class ArtistDetailsSeason extends Component {
|
|||
onTableOptionChange
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
albumCount,
|
||||
totalAlbumCount,
|
||||
trackFileCount,
|
||||
monitoredAlbumCount,
|
||||
sizeOnDisk,
|
||||
hasMonitoredAlbums
|
||||
} = getAlbumTypeStatistics(items);
|
||||
|
||||
const {
|
||||
isOrganizeModalOpen,
|
||||
isManageTracksOpen
|
||||
|
@ -137,25 +206,55 @@ class ArtistDetailsSeason extends Component {
|
|||
<div
|
||||
className={styles.albumType}
|
||||
>
|
||||
<Link
|
||||
className={styles.expandButton}
|
||||
onPress={this.onExpandPress}
|
||||
>
|
||||
<div className={styles.header}>
|
||||
<div className={styles.left}>
|
||||
{
|
||||
<div className={styles.header}>
|
||||
<div className={styles.left}>
|
||||
<MonitorToggleButton
|
||||
monitored={hasMonitoredAlbums}
|
||||
isDisabled={!artistMonitored}
|
||||
isSaving={isSaving}
|
||||
size={24}
|
||||
onPress={this.onMonitorAlbumsPress}
|
||||
/>
|
||||
<span className={styles.albumTypeLabel}>
|
||||
{label}
|
||||
</span>
|
||||
<Popover
|
||||
className={styles.albumCountTooltip}
|
||||
anchor={
|
||||
<Label
|
||||
size={sizes.LARGE}
|
||||
kind={getAlbumCountKind(hasMonitoredAlbums, albumCount, monitoredAlbumCount)}
|
||||
>
|
||||
<span>{albumCount} / {monitoredAlbumCount}</span>
|
||||
</Label>
|
||||
}
|
||||
title="Group Information"
|
||||
body={
|
||||
<div>
|
||||
<span className={styles.albumTypeLabel}>
|
||||
{label}
|
||||
</span>
|
||||
|
||||
<span className={styles.albumCount}>
|
||||
({items.length} Releases)
|
||||
</span>
|
||||
<AlbumGroupInfo
|
||||
totalAlbumCount={totalAlbumCount}
|
||||
monitoredAlbumCount={monitoredAlbumCount}
|
||||
trackFileCount={trackFileCount}
|
||||
sizeOnDisk={sizeOnDisk}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
position={tooltipPositions.BOTTOM}
|
||||
/>
|
||||
|
||||
</div>
|
||||
{
|
||||
sizeOnDisk ?
|
||||
<div className={styles.sizeOnDisk}>
|
||||
{formatBytes(sizeOnDisk)}
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
|
||||
<Link
|
||||
className={styles.expandButton}
|
||||
onPress={this.onExpandPress}
|
||||
>
|
||||
|
||||
<Icon
|
||||
className={styles.expandButtonIcon}
|
||||
|
@ -168,9 +267,9 @@ class ArtistDetailsSeason extends Component {
|
|||
!isSmallScreen &&
|
||||
<span> </span>
|
||||
}
|
||||
</Link>
|
||||
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{
|
||||
|
@ -238,16 +337,18 @@ ArtistDetailsSeason.propTypes = {
|
|||
artistId: PropTypes.number.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
artistMonitored: PropTypes.bool.isRequired,
|
||||
sortKey: PropTypes.string,
|
||||
sortDirection: PropTypes.oneOf(sortDirections.all),
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
isSaving: PropTypes.bool,
|
||||
isExpanded: PropTypes.bool,
|
||||
isSmallScreen: PropTypes.bool.isRequired,
|
||||
onTableOptionChange: PropTypes.func.isRequired,
|
||||
onExpandPress: PropTypes.func.isRequired,
|
||||
onSortPress: PropTypes.func.isRequired,
|
||||
onMonitorAlbumPress: PropTypes.func.isRequired,
|
||||
onMonitorAlbumsPress: PropTypes.func.isRequired,
|
||||
uiSettings: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
|
|
|
@ -36,9 +36,9 @@ function createMapStateToProps() {
|
|||
return {
|
||||
items: sortedAlbums,
|
||||
columns: albums.columns,
|
||||
artistMonitored: artist.monitored,
|
||||
sortKey: albums.sortKey,
|
||||
sortDirection: albums.sortDirection,
|
||||
artistMonitored: artist.monitored,
|
||||
isSmallScreen: dimensions.isSmallScreen,
|
||||
uiSettings
|
||||
};
|
||||
|
@ -66,7 +66,7 @@ class ArtistDetailsSeasonConnector extends Component {
|
|||
this.props.dispatchSetAlbumSort({ sortKey });
|
||||
};
|
||||
|
||||
onMonitorAlbumPress = (albumIds, monitored) => {
|
||||
onMonitorAlbumsPress = (albumIds, monitored) => {
|
||||
this.props.toggleAlbumsMonitored({
|
||||
albumIds,
|
||||
monitored
|
||||
|
@ -82,7 +82,7 @@ class ArtistDetailsSeasonConnector extends Component {
|
|||
{...this.props}
|
||||
onSortPress={this.onSortPress}
|
||||
onTableOptionChange={this.onTableOptionChange}
|
||||
onMonitorAlbumPress={this.onMonitorAlbumPress}
|
||||
onMonitorAlbumsPress={this.onMonitorAlbumsPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue