mirror of
https://github.com/Sonarr/Sonarr
synced 2024-12-25 17:27:18 +00:00
Pagination for missing is alive!
This commit is contained in:
parent
c9b9d7b956
commit
b4242f9fb2
17 changed files with 235 additions and 22 deletions
|
@ -7,6 +7,7 @@ using NzbDrone.Api.QualityProfiles;
|
|||
using NzbDrone.Api.QualityType;
|
||||
using NzbDrone.Api.Resolvers;
|
||||
using NzbDrone.Api.Series;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
@ -38,6 +39,9 @@ namespace NzbDrone.Api
|
|||
|
||||
//Episode
|
||||
Mapper.CreateMap<Episode, EpisodeResource>();
|
||||
|
||||
//Episode Paging
|
||||
Mapper.CreateMap<PagingSpec<Episode>, PagingResource<EpisodeResource>>();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -29,5 +29,6 @@ namespace NzbDrone.Api.Episodes
|
|||
public DateTime? GrabDate { get; set; }
|
||||
public PostDownloadStatusType PostDownloadStatus { get; set; }
|
||||
public Core.Tv.Series Series { get; set; }
|
||||
public String SeriesTitle { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using Nancy;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.Missing
|
||||
|
@ -25,11 +27,35 @@ namespace NzbDrone.Api.Missing
|
|||
bool includeSpecials;
|
||||
Boolean.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.IncludeSpecials), out includeSpecials);
|
||||
|
||||
var episodes = _episodeService.EpisodesWithoutFiles(includeSpecials);
|
||||
int pageSize;
|
||||
Int32.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.PageSize), out pageSize);
|
||||
if (pageSize == 0) pageSize = 20;
|
||||
|
||||
//TODO: Include the Series Title
|
||||
//TODO: Remove Take(20)
|
||||
return Mapper.Map<List<Episode>, List<EpisodeResource>>(episodes).Take(20).AsResponse();
|
||||
int page;
|
||||
Int32.TryParse(PrimitiveExtensions.ToNullSafeString(Request.Query.Page), out page);
|
||||
if (page == 0) page = 1;
|
||||
|
||||
var sortKey = PrimitiveExtensions.ToNullSafeString(Request.Query.SortKey)
|
||||
.Equals("SeriesTitle", StringComparison.InvariantCultureIgnoreCase)
|
||||
? "SeriesTitle"
|
||||
: "AirDate";
|
||||
|
||||
var sortDirection = PrimitiveExtensions.ToNullSafeString(Request.Query.SortDir)
|
||||
.Equals("Asc", StringComparison.InvariantCultureIgnoreCase)
|
||||
? ListSortDirection.Ascending
|
||||
: ListSortDirection.Descending;
|
||||
|
||||
var pagingSpec = new PagingSpec<Episode>
|
||||
{
|
||||
Page = page,
|
||||
PageSize = pageSize,
|
||||
SortKey = sortKey,
|
||||
SortDirection = sortDirection
|
||||
};
|
||||
|
||||
var result = _episodeService.EpisodesWithoutFiles(pagingSpec, includeSpecials);
|
||||
|
||||
return Mapper.Map<PagingSpec<Episode>, PagingResource<EpisodeResource>>(result).AsResponse();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -102,6 +102,7 @@
|
|||
<Compile Include="Mapping\ValueInjectorExtensions.cs" />
|
||||
<Compile Include="Missing\MissingModule.cs" />
|
||||
<Compile Include="NzbDroneRestModule.cs" />
|
||||
<Compile Include="PagingResource.cs" />
|
||||
<Compile Include="Resolvers\EndTimeResolver.cs" />
|
||||
<Compile Include="Resolvers\NextAiringResolver.cs" />
|
||||
<Compile Include="Resolvers\NullableDatetimeToString.cs" />
|
||||
|
|
15
NzbDrone.Api/PagingResource.cs
Normal file
15
NzbDrone.Api/PagingResource.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Api
|
||||
{
|
||||
public class PagingResource<TModel>
|
||||
{
|
||||
public int Page { get; set; }
|
||||
public string SortKey { get; set; }
|
||||
public int TotalRecords { get; set; }
|
||||
public List<TModel> Records { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
@ -38,15 +40,30 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
|||
[Test]
|
||||
public void should_get_episodes()
|
||||
{
|
||||
var episodes = Subject.EpisodesWithoutFiles(false);
|
||||
episodes.Should().HaveCount(1);
|
||||
var episodes =
|
||||
Subject.EpisodesWithoutFiles(new PagingSpec<Episode>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 10,
|
||||
SortKey = "AirDate",
|
||||
SortDirection = ListSortDirection.Ascending
|
||||
}, false);
|
||||
episodes.Records.Should().HaveCount(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[Ignore("Specials not implemented")]
|
||||
public void should_get_episode_including_specials()
|
||||
{
|
||||
var episodes = Subject.EpisodesWithoutFiles(true);
|
||||
episodes.Should().HaveCount(2);
|
||||
var episodes =
|
||||
Subject.EpisodesWithoutFiles(new PagingSpec<Episode>
|
||||
{
|
||||
Page = 1,
|
||||
PageSize = 10,
|
||||
SortKey = "AirDate",
|
||||
SortDirection = ListSortDirection.Ascending
|
||||
}, true);
|
||||
episodes.Records.Should().HaveCount(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,7 +114,6 @@ namespace NzbDrone.Core.Datastore
|
|||
return model;
|
||||
}
|
||||
|
||||
|
||||
public void Delete(TModel model)
|
||||
{
|
||||
_dataMapper.Delete<TModel>(c => c.Id == model.Id);
|
||||
|
@ -185,6 +184,5 @@ namespace NzbDrone.Core.Datastore
|
|||
.Entity(model)
|
||||
.Execute();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
18
NzbDrone.Core/Datastore/PagingSpec.cs
Normal file
18
NzbDrone.Core/Datastore/PagingSpec.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Datastore
|
||||
{
|
||||
public class PagingSpec<TModel>
|
||||
{
|
||||
public int Page { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
public int TotalRecords { get; set; }
|
||||
public string SortKey { get; set; }
|
||||
public ListSortDirection SortDirection { get; set; }
|
||||
public List<TModel> Records { get; set; }
|
||||
}
|
||||
}
|
|
@ -208,6 +208,7 @@
|
|||
<Compile Include="Datastore\MigrationType.cs" />
|
||||
<Compile Include="Datastore\ModelBase.cs" />
|
||||
<Compile Include="Datastore\BasicRepository.cs" />
|
||||
<Compile Include="Datastore\PagingSpec.cs" />
|
||||
<Compile Include="Datastore\RelationshipExtensions.cs" />
|
||||
<Compile Include="Datastore\TableMapping.cs" />
|
||||
<Compile Include="DecisionEngine\DownloadDecision.cs" />
|
||||
|
|
|
@ -71,6 +71,8 @@ namespace NzbDrone.Core.Tv
|
|||
}
|
||||
}
|
||||
|
||||
public String SeriesTitle { get; private set; }
|
||||
|
||||
public Series Series { get; set; }
|
||||
|
||||
public EpisodeFile EpisodeFile { get; set; }
|
||||
|
|
Binary file not shown.
|
@ -4,7 +4,9 @@ using System.Linq;
|
|||
using NLog;
|
||||
using NzbDrone.Common.Messaging;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Helpers;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.MetadataSource;
|
||||
using NzbDrone.Core.Model;
|
||||
|
@ -19,7 +21,7 @@ namespace NzbDrone.Core.Tv
|
|||
Episode GetEpisode(int seriesId, DateTime date);
|
||||
List<Episode> GetEpisodeBySeries(int seriesId);
|
||||
List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber);
|
||||
List<Episode> EpisodesWithoutFiles(bool includeSpecials);
|
||||
PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials);
|
||||
List<Episode> GetEpisodesByFileId(int episodeFileId);
|
||||
List<Episode> EpisodesWithFiles();
|
||||
void RefreshEpisodeInfo(Series series);
|
||||
|
@ -93,11 +95,13 @@ namespace NzbDrone.Core.Tv
|
|||
return _episodeRepository.GetEpisodes(seriesId, seasonNumber);
|
||||
}
|
||||
|
||||
public List<Episode> EpisodesWithoutFiles(bool includeSpecials)
|
||||
public PagingSpec<Episode> EpisodesWithoutFiles(PagingSpec<Episode> pagingSpec, bool includeSpecials)
|
||||
{
|
||||
var episodes = _episodeRepository.EpisodesWithoutFiles(includeSpecials);
|
||||
var episodeResult = _episodeRepository.EpisodesWithoutFiles(pagingSpec, includeSpecials);
|
||||
|
||||
return LinkSeriesToEpisodes(episodes);
|
||||
episodeResult.Records = LinkSeriesToEpisodes(episodeResult.Records);
|
||||
|
||||
return episodeResult;
|
||||
}
|
||||
|
||||
public List<Episode> GetEpisodesByFileId(int episodeFileId)
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
@param {boolean} [options.fastForwardHandleLabels] Whether to render fast forward buttons.
|
||||
*/
|
||||
initialize: function (options) {
|
||||
Backgrid.requireOptions(options, ["columns", "collection"]);
|
||||
//Backgrid.requireOptions(options, ["columns", "collection"]);
|
||||
|
||||
this.columns = options.columns;
|
||||
if (!(this.columns instanceof Backbone.Collection)) {
|
||||
|
|
|
@ -4,10 +4,6 @@ define(['app', 'Series/EpisodeModel'], function () {
|
|||
url : NzbDrone.Constants.ApiRoot + '/missing',
|
||||
model : NzbDrone.Series.EpisodeModel,
|
||||
|
||||
comparator: function (model) {
|
||||
return model.get('airDate');
|
||||
},
|
||||
|
||||
state: {
|
||||
pageSize: 10,
|
||||
sortKey: "airDate",
|
||||
|
@ -18,12 +14,24 @@ define(['app', 'Series/EpisodeModel'], function () {
|
|||
totalPages: null,
|
||||
totalRecords: null,
|
||||
pageSize: 'pageSize',
|
||||
sortKey: "sortBy",
|
||||
order: "direction",
|
||||
sortKey: "sortKey",
|
||||
order: "sortDir",
|
||||
directions: {
|
||||
"-1": "asc",
|
||||
"1": "desc"
|
||||
}
|
||||
},
|
||||
|
||||
parseState: function (resp, queryParams, state) {
|
||||
return {totalRecords: resp.totalRecords};
|
||||
},
|
||||
|
||||
parseRecords: function (resp) {
|
||||
if (resp) {
|
||||
return resp.records;
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
});
|
||||
});
|
|
@ -13,7 +13,8 @@ define([
|
|||
|
||||
regions: {
|
||||
missing: '#x-missing',
|
||||
toolbar: '#x-toolbar'
|
||||
toolbar: '#x-toolbar',
|
||||
pager : '#x-pager'
|
||||
},
|
||||
|
||||
showTable: function () {
|
||||
|
@ -48,6 +49,12 @@ define([
|
|||
editable : false,
|
||||
cell : 'airDate',
|
||||
headerCell: 'nzbDrone'
|
||||
// headerCell: Backgrid.NzbDroneHeaderCell.extend({
|
||||
// initialize: function(options) {
|
||||
// this.constructor.__super__.initialize.apply(this, [options]);
|
||||
// this.direction('descending');
|
||||
// }
|
||||
// })
|
||||
},
|
||||
{
|
||||
name : 'edit',
|
||||
|
@ -66,6 +73,13 @@ define([
|
|||
collection: this.missingCollection,
|
||||
className : 'table table-hover'
|
||||
}));
|
||||
|
||||
this.pager.show(new Backgrid.NzbDronePaginator({
|
||||
columns: columns,
|
||||
collection: this.missingCollection
|
||||
}));
|
||||
|
||||
this.missingCollection.getFirstPage();
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
|
|
|
@ -4,3 +4,8 @@
|
|||
<div id="x-missing"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<div id="x-pager"></div>
|
||||
</div>
|
||||
</div>
|
|
@ -40,6 +40,40 @@ Backgrid.NzbDroneHeaderCell = Backgrid.HeaderCell.extend({
|
|||
return this._direction;
|
||||
},
|
||||
|
||||
onClick: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var columnName = this.column.get("name");
|
||||
|
||||
if (this.column.get("sortable")) {
|
||||
if (this.direction() === "ascending") {
|
||||
this.sort(columnName, "descending", function (left, right) {
|
||||
var leftVal = left.get(columnName);
|
||||
var rightVal = right.get(columnName);
|
||||
if (leftVal === rightVal) {
|
||||
return 0;
|
||||
}
|
||||
else if (leftVal > rightVal) { return -1; }
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
else if (this.direction() === "descending") {
|
||||
this.sort(columnName, "ascending");
|
||||
}
|
||||
else {
|
||||
this.sort(columnName, "ascending", function (left, right) {
|
||||
var leftVal = left.get(columnName);
|
||||
var rightVal = right.get(columnName);
|
||||
if (leftVal === rightVal) {
|
||||
return 0;
|
||||
}
|
||||
else if (leftVal < rightVal) { return -1; }
|
||||
return 1;
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_convertDirectionToIcon: function (dir) {
|
||||
if (dir === 'ascending') {
|
||||
return 'icon-sort-up';
|
||||
|
@ -47,4 +81,69 @@ Backgrid.NzbDroneHeaderCell = Backgrid.HeaderCell.extend({
|
|||
|
||||
return 'icon-sort-down';
|
||||
}
|
||||
});
|
||||
|
||||
Backgrid.NzbDronePaginator = Backgrid.Extension.Paginator.extend({
|
||||
|
||||
events: {
|
||||
"click a": "changePage",
|
||||
"click i": "preventLinkClick"
|
||||
},
|
||||
|
||||
windowSize: 1,
|
||||
|
||||
fastForwardHandleLabels: {
|
||||
first: '<i class="icon-fast-backward"></i>',
|
||||
prev: '<i class="icon-backward"></i>',
|
||||
next: '<i class="icon-forward"></i>',
|
||||
last: '<i class="icon-fast-forward"></i>'
|
||||
},
|
||||
|
||||
changePage: function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
var target = $(e.target);
|
||||
|
||||
if (target.closest('li').hasClass('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!$(target).is('a')){
|
||||
target = target.parent('a');
|
||||
}
|
||||
|
||||
var label = target.html();
|
||||
var ffLabels = this.fastForwardHandleLabels;
|
||||
|
||||
var collection = this.collection;
|
||||
|
||||
if (ffLabels) {
|
||||
switch (label) {
|
||||
case ffLabels.first:
|
||||
collection.getFirstPage();
|
||||
return;
|
||||
case ffLabels.prev:
|
||||
if (collection.hasPrevious()) {
|
||||
collection.getPreviousPage();
|
||||
}
|
||||
return;
|
||||
case ffLabels.next:
|
||||
if (collection.hasNext()) {
|
||||
collection.getNextPage();
|
||||
}
|
||||
return;
|
||||
case ffLabels.last:
|
||||
collection.getLastPage();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var state = collection.state;
|
||||
var pageIndex = $(e.target).text() * 1;
|
||||
collection.getPage(state.firstPage === 0 ? pageIndex - 1 : pageIndex);
|
||||
},
|
||||
|
||||
preventLinkClick: function (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
Loading…
Reference in a new issue