diff --git a/frontend/src/Artist/Details/AlbumGroupInfo.css b/frontend/src/Artist/Details/AlbumGroupInfo.css new file mode 100644 index 000000000..b3102d230 --- /dev/null +++ b/frontend/src/Artist/Details/AlbumGroupInfo.css @@ -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; +} diff --git a/frontend/src/Artist/Details/AlbumGroupInfo.js b/frontend/src/Artist/Details/AlbumGroupInfo.js new file mode 100644 index 000000000..0702290c9 --- /dev/null +++ b/frontend/src/Artist/Details/AlbumGroupInfo.js @@ -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 ( + + + + + + + + + + ); +} + +AlbumGroupInfo.propTypes = { + totalAlbumCount: PropTypes.number.isRequired, + monitoredAlbumCount: PropTypes.number.isRequired, + trackFileCount: PropTypes.number.isRequired, + sizeOnDisk: PropTypes.number.isRequired +}; + +export default AlbumGroupInfo; diff --git a/frontend/src/Artist/Details/ArtistDetailsSeason.css b/frontend/src/Artist/Details/ArtistDetailsSeason.css index b1cb2632e..4421fe7a7 100644 --- a/frontend/src/Artist/Details/ArtistDetailsSeason.css +++ b/frontend/src/Artist/Details/ArtistDetailsSeason.css @@ -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; + } } diff --git a/frontend/src/Artist/Details/ArtistDetailsSeason.js b/frontend/src/Artist/Details/ArtistDetailsSeason.js index 349184814..e0cbfc87c 100644 --- a/frontend/src/Artist/Details/ArtistDetailsSeason.js +++ b/frontend/src/Artist/Details/ArtistDetailsSeason.js @@ -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 {
- -
-
- { +
+
+ + + {label} + + + {albumCount} / {monitoredAlbumCount} + + } + title="Group Information" + body={
- - {label} - - - - ({items.length} Releases) - +
} + position={tooltipPositions.BOTTOM} + /> -
+ { + sizeOnDisk ? +
+ {formatBytes(sizeOnDisk)} +
: + null + } +
+ +   } + -
- +
{ @@ -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 }; diff --git a/frontend/src/Artist/Details/ArtistDetailsSeasonConnector.js b/frontend/src/Artist/Details/ArtistDetailsSeasonConnector.js index daa99e49a..6eb98cd52 100644 --- a/frontend/src/Artist/Details/ArtistDetailsSeasonConnector.js +++ b/frontend/src/Artist/Details/ArtistDetailsSeasonConnector.js @@ -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} /> ); }