[UI Work] History, Queue, Calendar Fixes

pull/6/head
Qstick 7 years ago
parent d2bafd4605
commit 871a3773b2

@ -30,16 +30,16 @@ class History extends Component {
filterKey, filterKey,
filterValue, filterValue,
totalRecords, totalRecords,
isEpisodesFetching, isAlbumsFetching,
isEpisodesPopulated, isAlbumsPopulated,
episodesError, episodesError,
onFilterSelect, onFilterSelect,
onFirstPagePress, onFirstPagePress,
...otherProps ...otherProps
} = this.props; } = this.props;
const isFetchingAny = isFetching || isEpisodesFetching; const isFetchingAny = isFetching || isAlbumsFetching;
const isAllPopulated = isPopulated && (isEpisodesPopulated || !items.length); const isAllPopulated = isPopulated && (isAlbumsPopulated || !items.length);
const hasError = error || episodesError; const hasError = error || episodesError;
return ( return (
@ -132,7 +132,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 episodes to populate because they are never coming. // wait for the albums to populate because they are never coming.
isPopulated && !hasError && !items.length && isPopulated && !hasError && !items.length &&
<div> <div>
@ -185,8 +185,8 @@ History.propTypes = {
filterKey: PropTypes.string, filterKey: PropTypes.string,
filterValue: PropTypes.string, filterValue: PropTypes.string,
totalRecords: PropTypes.number, totalRecords: PropTypes.number,
isEpisodesFetching: PropTypes.bool.isRequired, isAlbumsFetching: PropTypes.bool.isRequired,
isEpisodesPopulated: PropTypes.bool.isRequired, isAlbumsPopulated: PropTypes.bool.isRequired,
episodesError: PropTypes.object, episodesError: PropTypes.object,
onFilterSelect: PropTypes.func.isRequired, onFilterSelect: PropTypes.func.isRequired,
onFirstPagePress: PropTypes.func.isRequired onFirstPagePress: PropTypes.func.isRequired

@ -14,8 +14,8 @@ function createMapStateToProps() {
(state) => state.episodes, (state) => state.episodes,
(history, episodes) => { (history, episodes) => {
return { return {
isEpisodesFetching: episodes.isFetching, isAlbumsFetching: episodes.isFetching,
isEpisodesPopulated: episodes.isPopulated, isAlbumsPopulated: episodes.isPopulated,
episodesError: episodes.error, episodesError: episodes.error,
...history ...history
}; };
@ -40,8 +40,8 @@ class HistoryConnector extends Component {
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (hasDifferentItems(prevProps.items, this.props.items)) { if (hasDifferentItems(prevProps.items, this.props.items)) {
const episodeIds = selectUniqueIds(this.props.items, 'episodeId'); const albumIds = selectUniqueIds(this.props.items, 'albumId');
this.props.fetchEpisodes({ episodeIds }); this.props.fetchEpisodes({ albumIds });
} }
} }

@ -36,17 +36,17 @@ function getIconKind(eventType) {
function getTooltip(eventType, data) { function getTooltip(eventType, data) {
switch (eventType) { switch (eventType) {
case 'grabbed': case 'grabbed':
return `Episode grabbed from ${data.indexer} and sent to ${data.downloadClient}`; return `Album grabbed from ${data.indexer} and sent to ${data.downloadClient}`;
case 'seriesFolderImported': case 'seriesFolderImported':
return 'Episode imported from series folder'; return 'Album imported from artist folder';
case 'downloadFolderImported': case 'downloadFolderImported':
return 'Episode downloaded successfully and picked up from download client'; return 'Album downloaded successfully and picked up from download client';
case 'downloadFailed': case 'downloadFailed':
return 'Episode download failed'; return 'Album download failed';
case 'episodeFileDeleted': case 'episodeFileDeleted':
return 'Episode file deleted'; return 'Track file deleted';
case 'episodeFileRenamed': case 'episodeFileRenamed':
return 'Episode file renamed'; return 'Track file renamed';
default: default:
return 'Unknown event'; return 'Unknown event';
} }

@ -6,7 +6,6 @@ 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 episodeEntities from 'Episode/episodeEntities'; import episodeEntities from 'Episode/episodeEntities';
import SeasonEpisodeNumber from 'Episode/SeasonEpisodeNumber';
import EpisodeTitleLink from 'Episode/EpisodeTitleLink'; import EpisodeTitleLink from 'Episode/EpisodeTitleLink';
import EpisodeLanguage from 'Episode/EpisodeLanguage'; import EpisodeLanguage from 'Episode/EpisodeLanguage';
import EpisodeQuality from 'Episode/EpisodeQuality'; import EpisodeQuality from 'Episode/EpisodeQuality';
@ -54,9 +53,9 @@ class HistoryRow extends Component {
render() { render() {
const { const {
episodeId, albumId,
series, artist,
episode, album,
language, language,
quality, quality,
eventType, eventType,
@ -70,7 +69,7 @@ class HistoryRow extends Component {
onMarkAsFailedPress onMarkAsFailedPress
} = this.props; } = this.props;
if (!episode) { if (!album) {
return null; return null;
} }
@ -97,28 +96,12 @@ class HistoryRow extends Component {
); );
} }
if (name === 'series.sortTitle') { if (name === 'artist.sortName') {
return ( return (
<TableRowCell key={name}> <TableRowCell key={name}>
<ArtistNameLink <ArtistNameLink
titleSlug={series.titleSlug} nameSlug={artist.nameSlug}
title={series.title} artistName={artist.artistName}
/>
</TableRowCell>
);
}
if (name === 'episode') {
return (
<TableRowCell key={name}>
<SeasonEpisodeNumber
seasonNumber={episode.seasonNumber}
episodeNumber={episode.episodeNumber}
absoluteEpisodeNumber={episode.absoluteEpisodeNumber}
seriesType={series.seriesType}
sceneSeasonNumber={episode.sceneSeasonNumber}
sceneEpisodeNumber={episode.sceneEpisodeNumber}
sceneAbsoluteEpisodeNumber={episode.sceneAbsoluteEpisodeNumber}
/> />
</TableRowCell> </TableRowCell>
); );
@ -128,10 +111,10 @@ class HistoryRow extends Component {
return ( return (
<TableRowCell key={name}> <TableRowCell key={name}>
<EpisodeTitleLink <EpisodeTitleLink
episodeId={episodeId} episodeId={albumId}
episodeEntity={episodeEntities.EPISODES} episodeEntity={episodeEntities.EPISODES}
artistId={series.id} artistId={artist.id}
episodeTitle={episode.title} episodeTitle={album.title}
showOpenSeriesButton={true} showOpenSeriesButton={true}
/> />
</TableRowCell> </TableRowCell>
@ -234,9 +217,9 @@ class HistoryRow extends Component {
} }
HistoryRow.propTypes = { HistoryRow.propTypes = {
episodeId: PropTypes.number, albumId: PropTypes.number,
series: PropTypes.object.isRequired, artist: PropTypes.object.isRequired,
episode: PropTypes.object, album: PropTypes.object,
language: PropTypes.object.isRequired, language: PropTypes.object.isRequired,
quality: PropTypes.object.isRequired, quality: PropTypes.object.isRequired,
eventType: PropTypes.string.isRequired, eventType: PropTypes.string.isRequired,

@ -100,7 +100,7 @@ class Queue extends Component {
isPopulated, isPopulated,
error, error,
items, items,
isEpisodesPopulated, isAlbumsPopulated,
columns, columns,
totalRecords, totalRecords,
isGrabbing, isGrabbing,
@ -119,7 +119,7 @@ class Queue extends Component {
} = this.state; } = this.state;
const isRefreshing = isFetching || isCheckForFinishedDownloadExecuting; const isRefreshing = isFetching || isCheckForFinishedDownloadExecuting;
const isAllPopulated = isPopulated && (isEpisodesPopulated || !items.length); const isAllPopulated = isPopulated && (isAlbumsPopulated || !items.length);
const selectedCount = this.getSelectedIds().length; const selectedCount = this.getSelectedIds().length;
const disableSelectedActions = selectedCount === 0; const disableSelectedActions = selectedCount === 0;
@ -191,7 +191,7 @@ class Queue extends Component {
return ( return (
<QueueRowConnector <QueueRowConnector
key={item.id} key={item.id}
episodeId={item.episode.id} episodeId={item.album.id}
episodeEntity={episodeEntities.QUEUE_EPISODES} episodeEntity={episodeEntities.QUEUE_EPISODES}
isSelected={selectedState[item.id]} isSelected={selectedState[item.id]}
columns={columns} columns={columns}
@ -229,7 +229,7 @@ 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,
isEpisodesPopulated: PropTypes.bool.isRequired, isAlbumsPopulated: PropTypes.bool.isRequired,
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,

@ -21,7 +21,7 @@ function createMapStateToProps() {
return { return {
isCheckForFinishedDownloadExecuting, isCheckForFinishedDownloadExecuting,
isEpisodesPopulated: queueEpisodes.isPopulated, isAlbumsPopulated: queueEpisodes.isPopulated,
...queue ...queue
}; };
} }
@ -46,7 +46,7 @@ class QueueConnector extends Component {
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (hasDifferentItems(prevProps.items, this.props.items)) { if (hasDifferentItems(prevProps.items, this.props.items)) {
const episodes = _.uniqBy(_.reduce(this.props.items, (result, item) => { const episodes = _.uniqBy(_.reduce(this.props.items, (result, item) => {
result.push(item.episode); result.push(item.album);
return result; return result;
}, []), ({ id }) => id); }, []), ({ id }) => id);

@ -132,12 +132,12 @@ class QueueRow extends Component {
); );
} }
if (name === 'series.sortTitle') { if (name === 'series.sortName') {
return ( return (
<TableRowCell key={name}> <TableRowCell key={name}>
<ArtistNameLink <ArtistNameLink
titleSlug={series.titleSlug} nameSlug={series.nameSlug}
title={series.title} artistName={series.artistName}
/> />
</TableRowCell> </TableRowCell>
); );
@ -147,24 +147,8 @@ class QueueRow extends Component {
return ( return (
<TableRowCell key={name}> <TableRowCell key={name}>
<ArtistNameLink <ArtistNameLink
titleSlug={series.titleSlug} nameSlug={series.nameSlug}
title={series.title} artistName={series.artistName}
/>
</TableRowCell>
);
}
if (name === 'episode') {
return (
<TableRowCell key={name}>
<SeasonEpisodeNumber
seasonNumber={episode.seasonNumber}
episodeNumber={episode.episodeNumber}
absoluteEpisodeNumber={episode.absoluteEpisodeNumber}
seriesType={series.seriesType}
sceneSeasonNumber={episode.sceneSeasonNumber}
sceneEpisodeNumber={episode.sceneEpisodeNumber}
sceneAbsoluteEpisodeNumber={episode.sceneAbsoluteEpisodeNumber}
/> />
</TableRowCell> </TableRowCell>
); );
@ -316,7 +300,7 @@ QueueRow.propTypes = {
status: PropTypes.string.isRequired, status: PropTypes.string.isRequired,
trackedDownloadStatus: PropTypes.string, trackedDownloadStatus: PropTypes.string,
statusMessages: PropTypes.arrayOf(PropTypes.object), statusMessages: PropTypes.arrayOf(PropTypes.object),
errorMessage: PropTypes.string.isRequired, errorMessage: PropTypes.string,
series: PropTypes.object.isRequired, series: PropTypes.object.isRequired,
episode: PropTypes.object.isRequired, episode: PropTypes.object.isRequired,
quality: PropTypes.object.isRequired, quality: PropTypes.object.isRequired,

@ -51,14 +51,14 @@ class CalendarConnector extends Component {
} = this.props; } = this.props;
if (hasDifferentItems(prevProps.items, items)) { if (hasDifferentItems(prevProps.items, items)) {
const episodeIds = selectUniqueIds(items, 'id'); const albumIds = selectUniqueIds(items, 'id');
const episodeFileIds = selectUniqueIds(items, 'episodeFileId'); // const episodeFileIds = selectUniqueIds(items, 'episodeFileId');
this.props.fetchQueueDetails({ episodeIds }); this.props.fetchQueueDetails({ albumIds });
if (episodeFileIds.length) { // if (episodeFileIds.length) {
this.props.fetchEpisodeFiles({ episodeFileIds }); // this.props.fetchEpisodeFiles({ episodeFileIds });
} // }
} }
if (prevProps.time !== time) { if (prevProps.time !== time) {

@ -54,7 +54,7 @@ class CalendarEvent extends Component {
// absoluteEpisodeNumber, // absoluteEpisodeNumber,
releaseDate, releaseDate,
monitored, monitored,
hasFile, // hasFile,
grabbed, grabbed,
queueItem, queueItem,
// timeFormat, // timeFormat,
@ -65,7 +65,7 @@ class CalendarEvent extends Component {
// const endTime = startTime.add(artist.runtime, 'minutes'); // const endTime = startTime.add(artist.runtime, 'minutes');
const downloading = !!(queueItem || grabbed); const downloading = !!(queueItem || grabbed);
const isMonitored = artist.monitored && monitored; const isMonitored = artist.monitored && monitored;
const statusStyle = getStatusStyle(id, hasFile, downloading, startTime, isMonitored); const statusStyle = getStatusStyle(id, downloading, startTime, isMonitored);
// const missingAbsoluteNumber = artist.seriesType === 'anime' && seasonNumber > 0 && !absoluteEpisodeNumber; // const missingAbsoluteNumber = artist.seriesType === 'anime' && seasonNumber > 0 && !absoluteEpisodeNumber;
return ( return (
@ -133,7 +133,7 @@ CalendarEvent.propTypes = {
// absoluteEpisodeNumber: PropTypes.number, // absoluteEpisodeNumber: PropTypes.number,
releaseDate: PropTypes.string.isRequired, releaseDate: PropTypes.string.isRequired,
monitored: PropTypes.bool.isRequired, monitored: PropTypes.bool.isRequired,
hasFile: PropTypes.bool.isRequired, // hasFile: PropTypes.bool.isRequired,
grabbed: PropTypes.bool, grabbed: PropTypes.bool,
queueItem: PropTypes.object, queueItem: PropTypes.object,
// timeFormat: PropTypes.string.isRequired, // timeFormat: PropTypes.string.isRequired,

@ -1,11 +1,11 @@
import moment from 'moment'; import moment from 'moment';
function getStatusStyle(episodeNumber, hasFile, downloading, startTime, isMonitored) { function getStatusStyle(episodeNumber, downloading, startTime, isMonitored) {
const currentTime = moment(); const currentTime = moment();
if (hasFile) { // if (hasFile) {
return 'downloaded'; // return 'downloaded';
} // }
if (downloading) { if (downloading) {
return 'downloading'; return 'downloading';

@ -27,19 +27,14 @@ export const defaultState = {
isModifiable: false isModifiable: false
}, },
{ {
name: 'series.sortTitle', name: 'artist.sortName',
label: 'Series', label: 'Artist',
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{
name: 'episode',
label: 'Episode',
isVisible: true
},
{ {
name: 'episodeTitle', name: 'episodeTitle',
label: 'Episode Title', label: 'Album Title',
isVisible: true isVisible: true
}, },
{ {

@ -45,19 +45,14 @@ export const defaultState = {
isModifiable: false isModifiable: false
}, },
{ {
name: 'series.sortTitle', name: 'series.sortName',
label: 'Series', label: 'Artist',
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{
name: 'episode',
label: 'Episode',
isVisible: true
},
{ {
name: 'episodeTitle', name: 'episodeTitle',
label: 'Episode Title', label: 'Album Title',
isVisible: true isVisible: true
}, },
{ {

@ -11,7 +11,7 @@ function createQueueItemSelector() {
} }
return _.find(details.items, (item) => { return _.find(details.items, (item) => {
return item.episode.id === episodeId; return item.album.id === episodeId;
}); });
} }
); );

@ -51,10 +51,10 @@ class CutoffUnmetConnector extends Component {
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (hasDifferentItems(prevProps.items, this.props.items)) { if (hasDifferentItems(prevProps.items, this.props.items)) {
const episodeIds = selectUniqueIds(this.props.items, 'id'); const albumIds = selectUniqueIds(this.props.items, 'id');
const episodeFileIds = selectUniqueIds(this.props.items, 'episodeFileId'); const episodeFileIds = selectUniqueIds(this.props.items, 'episodeFileId');
this.props.fetchQueueDetails({ episodeIds }); this.props.fetchQueueDetails({ albumIds });
if (episodeFileIds.length) { if (episodeFileIds.length) {
this.props.fetchEpisodeFiles({ episodeFileIds }); this.props.fetchEpisodeFiles({ episodeFileIds });

@ -48,8 +48,8 @@ class MissingConnector extends Component {
componentDidUpdate(prevProps) { componentDidUpdate(prevProps) {
if (hasDifferentItems(prevProps.items, this.props.items)) { if (hasDifferentItems(prevProps.items, this.props.items)) {
const episodeIds = selectUniqueIds(this.props.items, 'id'); const albumIds = selectUniqueIds(this.props.items, 'id');
this.props.fetchQueueDetails({ episodeIds }); this.props.fetchQueueDetails({ albumIds });
} }
} }

@ -27,16 +27,28 @@ namespace Lidarr.Api.V3.Albums
private List<AlbumResource> GetAlbums() private List<AlbumResource> GetAlbums()
{ {
if (!Request.Query.ArtistId.HasValue) var artistIdQuery = Request.Query.ArtistId;
var albumIdsQuery = Request.Query.AlbumIds;
if (!Request.Query.ArtistId.HasValue && !albumIdsQuery.HasValue)
{ {
throw new BadRequestException("artistId is missing"); throw new BadRequestException("artistId or albumIds must be provided");
}
if (artistIdQuery.HasValue)
{
int artistId = Convert.ToInt32(artistIdQuery.Value);
return MapToResource(_albumService.GetAlbumsByArtist(artistId), false);
} }
var artistId = (int)Request.Query.ArtistId; string episodeIdsValue = albumIdsQuery.Value.ToString();
var resources = MapToResource(_albumService.GetAlbumsByArtist(artistId), false); var episodeIds = episodeIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(e => Convert.ToInt32(e))
.ToList();
return resources; return MapToResource(_albumService.GetAlbums(episodeIds), false);
} }
private Response SetAlbumMonitored(int id) private Response SetAlbumMonitored(int id)

@ -33,23 +33,23 @@ namespace Lidarr.Api.V3.Queue
var pending = _pendingReleaseService.GetPendingQueue(); var pending = _pendingReleaseService.GetPendingQueue();
var fullQueue = queue.Concat(pending); var fullQueue = queue.Concat(pending);
var seriesIdQuery = Request.Query.SeriesId; var artistIdQuery = Request.Query.ArtistId;
var episodeIdsQuery = Request.Query.EpisodeIds; var albumIdsQuery = Request.Query.AlbumIds;
if (seriesIdQuery.HasValue) if (artistIdQuery.HasValue)
{ {
return fullQueue.Where(q => q.Artist.Id == (int)seriesIdQuery).ToResource(includeSeries, includeEpisode); return fullQueue.Where(q => q.Artist.Id == (int)artistIdQuery).ToResource(includeSeries, includeEpisode);
} }
if (episodeIdsQuery.HasValue) if (albumIdsQuery.HasValue)
{ {
string episodeIdsValue = episodeIdsQuery.Value.ToString(); string albumIdsValue = albumIdsQuery.Value.ToString();
var episodeIds = episodeIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) var albumIds = albumIdsValue.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(e => Convert.ToInt32(e)) .Select(e => Convert.ToInt32(e))
.ToList(); .ToList();
return fullQueue.Where(q => episodeIds.Contains(q.Episode.Id)).ToResource(includeSeries, includeEpisode); return fullQueue.Where(q => albumIds.Contains(q.Album.Id)).ToResource(includeSeries, includeEpisode);
} }
return fullQueue.ToResource(includeSeries, includeEpisode); return fullQueue.ToResource(includeSeries, includeEpisode);

Loading…
Cancel
Save