Merge branch 'view-filtering' of https://github.com/Taloth/NzbDrone into view-filtering

pull/6/head
markus101 11 years ago
commit 9515c28729

@ -23,6 +23,31 @@ namespace NzbDrone.Api.Logs
pageSpec.SortKey = "id"; pageSpec.SortKey = "id";
} }
if (pagingResource.FilterKey == "level")
{
switch (pagingResource.FilterValue)
{
case "Fatal":
pageSpec.FilterExpression = h => h.Level == "Fatal";
break;
case "Error":
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error";
break;
case "Warn":
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn";
break;
case "Info":
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info";
break;
case "Debug":
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug";
break;
case "Trace":
pageSpec.FilterExpression = h => h.Level == "Fatal" || h.Level == "Error" || h.Level == "Warn" || h.Level == "Info" || h.Level == "Debug" || h.Level == "Trace";
break;
}
}
return ApplyToPage(_logService.Paged, pageSpec); return ApplyToPage(_logService.Paged, pageSpec);
} }
} }

@ -9,6 +9,8 @@ namespace NzbDrone.Api
public int PageSize { get; set; } public int PageSize { get; set; }
public string SortKey { get; set; } public string SortKey { get; set; }
public SortDirection SortDirection { get; set; } public SortDirection SortDirection { get; set; }
public string FilterKey { get; set; }
public string FilterValue { get; set; }
public int TotalRecords { get; set; } public int TotalRecords { get; set; }
public List<TModel> Records { get; set; } public List<TModel> Records { get; set; }
} }

@ -241,6 +241,16 @@ namespace NzbDrone.Api.REST
} }
} }
if (Request.Query.FilterKey != null)
{
pagingResource.FilterKey = Request.Query.FilterKey.ToString();
if (Request.Query.FilterValue != null)
{
pagingResource.FilterValue = Request.Query.FilterValue.ToString();
}
}
return pagingResource; return pagingResource;
} }
} }

@ -210,18 +210,20 @@ namespace NzbDrone.Core.Datastore
public virtual PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec) public virtual PagingSpec<TModel> GetPaged(PagingSpec<TModel> pagingSpec)
{ {
var pagingQuery = Query.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection()) pagingSpec.Records = GetPagedQuery(Query, pagingSpec).ToList();
.Skip(pagingSpec.PagingOffset()) pagingSpec.TotalRecords = GetPagedQuery(Query, pagingSpec).GetRowCount();
.Take(pagingSpec.PageSize);
pagingSpec.Records = pagingQuery.ToList();
//TODO: Use the same query for count and records
pagingSpec.TotalRecords = Count();
return pagingSpec; return pagingSpec;
} }
protected virtual SortBuilder<TModel> GetPagedQuery(QueryBuilder<TModel> query, PagingSpec<TModel> pagingSpec)
{
return query.Where(pagingSpec.FilterExpression)
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
.Skip(pagingSpec.PagingOffset())
.Take(pagingSpec.PageSize);
}
public void DeleteAll() public void DeleteAll()
{ {
DataMapper.Delete<TModel>(c => c.Id > 0); DataMapper.Delete<TModel>(c => c.Id > 0);

@ -67,22 +67,12 @@ namespace NzbDrone.Core.History
.FirstOrDefault(); .FirstOrDefault();
} }
public override PagingSpec<History> GetPaged(PagingSpec<History> pagingSpec) protected override SortBuilder<History> GetPagedQuery(QueryBuilder<History> query, PagingSpec<History> pagingSpec)
{ {
pagingSpec.Records = GetPagedQuery(pagingSpec).ToList(); var baseQuery = query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id)
pagingSpec.TotalRecords = GetPagedQuery(pagingSpec).GetRowCount(); .Join<History, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id);
return pagingSpec; return base.GetPagedQuery(baseQuery, pagingSpec);
}
private SortBuilder<History> GetPagedQuery(PagingSpec<History> pagingSpec)
{
return Query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id)
.Join<History, Episode>(JoinType.Inner, h => h.Episode, (h, e) => h.EpisodeId == e.Id)
.Where(pagingSpec.FilterExpression)
.OrderBy(pagingSpec.OrderByClause(), pagingSpec.ToSortDirection())
.Skip(pagingSpec.PagingOffset())
.Take(pagingSpec.PageSize);
} }
} }
} }

@ -259,7 +259,7 @@
}; };
// A list of options to be attached directly to the model, if provided. // A list of options to be attached directly to the model, if provided.
var modelOptions = ['url', 'urlRoot', 'collection']; var modelOptions = ['urlRoot', 'collection'];
// Attach all inheritable methods to the Model prototype. // Attach all inheritable methods to the Model prototype.
_.extend(Model.prototype, Events, { _.extend(Model.prototype, Events, {

@ -0,0 +1,78 @@
'use strict';
define(
[
'underscore',
'backbone'],
function (_, Backbone) {
return function () {
this.prototype.setFilter = function(filter, options) {
options = _.extend({ reset: true }, options || {});
this.state.filterKey = filter[0];
this.state.filterValue = filter[1];
if (options.reset) {
if (this.mode != 'server') {
this.fullCollection.resetFiltered();
} else {
return this.fetch();
}
}
};
this.prototype.setFilterMode = function(mode, options) {
this.setFilter(this.filterModes[mode], options);
};
var originalMakeFullCollection = this.prototype._makeFullCollection;
this.prototype._makeFullCollection = function (models, options) {
var self = this;
self.shadowCollection = originalMakeFullCollection.apply(this, [models, options]);
var filterModel = function(model) {
if (!self.state.filterKey || !self.state.filterValue)
return true;
else
return model.get(self.state.filterKey) === self.state.filterValue;
};
self.shadowCollection.filtered = function() {
return this.filter(filterModel);
};
var filteredModels = self.shadowCollection.filtered();
var fullCollection = originalMakeFullCollection.apply(this, [filteredModels, options]);
fullCollection.resetFiltered = function(options) {
Backbone.Collection.prototype.reset.apply(this, [self.shadowCollection.filtered(), options]);
};
fullCollection.reset = function (models, options) {
self.shadowCollection.reset(models, options);
self.fullCollection.resetFiltered();
};
return fullCollection;
};
_.extend(this.prototype.state, {
filterKey : null,
filterValue : null
});
_.extend(this.prototype.queryParams, {
filterKey : 'filterKey',
filterValue : 'filterValue'
});
return this;
};
}
);

@ -62,23 +62,20 @@ define(
return '1'; return '1';
}; };
_.extend(this.prototype, { var originalMakeComparator = this.prototype._makeComparator;
initialSort: function () { this.prototype._makeComparator = function (sortKey, order, sortValue) {
var key = this.state.sortKey; var state = this.state;
var order = this.state.order;
sortKey = sortKey || state.sortKey;
if (this[key] && this.mode === 'client') { order = order || state.order;
var sortValue = this[key];
if (!sortKey || !order) return;
this.setSorting(key, order, { sortValue: sortValue });
if (!sortValue && this[sortKey]) sortValue = this[sortKey];
var comparator = this._makeComparator(key, order, sortValue);
this.fullCollection.comparator = comparator; return originalMakeComparator.call(this, sortKey, order, sortValue);
this.fullCollection.sort(); };
}
}
});
return this; return this;
}; };

@ -127,46 +127,84 @@ define(
] ]
}, },
sortingOptions: {
type : 'sorting',
storeState : false,
viewCollection: SeriesCollection,
items :
[
{
title: 'Title',
name : 'title'
},
{
title: 'Seasons',
name : 'seasonCount'
},
{
title: 'Quality',
name : 'qualityProfileId'
},
{
title: 'Network',
name : 'network'
},
{
title : 'Next Airing',
name : 'nextAiring',
sortValue : SeriesCollection.nextAiring
},
{
title: 'Episodes',
name : 'percentOfEpisodes'
}
]
},
initialize: function () { initialize: function () {
this.seriesCollection = SeriesCollection; this.seriesCollection = SeriesCollection.clone();
this.listenTo(SeriesCollection, 'sync', this._renderView); this.listenTo(SeriesCollection, 'sync', this._renderView);
this.listenTo(SeriesCollection, 'remove', this._renderView); this.listenTo(SeriesCollection, 'remove', this._renderView);
this.sortingOptions = {
type : 'sorting',
storeState : false,
viewCollection: this.seriesCollection,
items :
[
{
title: 'Title',
name : 'title'
},
{
title: 'Seasons',
name : 'seasonCount'
},
{
title: 'Quality',
name : 'qualityProfileId'
},
{
title: 'Network',
name : 'network'
},
{
title : 'Next Airing',
name : 'nextAiring',
sortValue : SeriesCollection.nextAiring
},
{
title: 'Episodes',
name : 'percentOfEpisodes'
}
]
};
this.filteringOptions = {
type : 'radio',
storeState : true,
menuKey : 'series.filterMode',
defaultAction: 'all',
items :
[
{
key : 'all',
title : '',
tooltip : 'All',
icon : 'icon-circle-blank',
callback: this._setFilter
},
{
key : 'monitored',
title : '',
tooltip : 'Monitored Only',
icon : 'icon-nd-monitored',
callback: this._setFilter
},
{
key : 'continuing',
title : '',
tooltip : 'Continuing Only',
icon : 'icon-play',
callback: this._setFilter
},
{
key : 'ended',
title : '',
tooltip : 'Ended Only',
icon : 'icon-stop',
callback: this._setFilter
}
]
};
this.viewButtons = { this.viewButtons = {
type : 'radio', type : 'radio',
storeState : true, storeState : true,
@ -201,26 +239,30 @@ define(
_showTable: function () { _showTable: function () {
this.currentView = new Backgrid.Grid({ this.currentView = new Backgrid.Grid({
collection: SeriesCollection, collection: this.seriesCollection,
columns : this.columns, columns : this.columns,
className : 'table table-hover' className : 'table table-hover'
}); });
this._fetchCollection(); this._renderView();
}, },
_showList: function () { _showList: function () {
this.currentView = new ListCollectionView({ collection: SeriesCollection }); this.currentView = new ListCollectionView({
collection: this.seriesCollection
});
this._fetchCollection(); this._renderView();
}, },
_showPosters: function () { _showPosters: function () {
this.currentView = new PosterCollectionView({ collection: SeriesCollection }); this.currentView = new PosterCollectionView({
collection: this.seriesCollection
});
this._fetchCollection(); this._renderView();
}, },
_renderView: function () { _renderView: function () {
if (SeriesCollection.length === 0) { if (SeriesCollection.length === 0) {
@ -238,10 +280,17 @@ define(
onShow: function () { onShow: function () {
this._showToolbar(); this._showToolbar();
this._renderView(); this._renderView();
this._fetchCollection();
}, },
_fetchCollection: function () { _fetchCollection: function () {
SeriesCollection.fetch(); this.seriesCollection.fetch();
},
_setFilter: function(buttonContext) {
var mode = buttonContext.model.get('key');
this.seriesCollection.setFilterMode(mode);
}, },
_showToolbar: function () { _showToolbar: function () {
@ -251,11 +300,11 @@ define(
} }
var rightButtons = [ var rightButtons = [
this.sortingOptions,
this.filteringOptions,
this.viewButtons this.viewButtons
]; ];
rightButtons.splice(0, 0, this.sortingOptions);
this.toolbar.show(new ToolbarLayout({ this.toolbar.show(new ToolbarLayout({
right : rightButtons, right : rightButtons,
left : left :

@ -6,9 +6,10 @@ define(
'backbone.pageable', 'backbone.pageable',
'Series/SeriesModel', 'Series/SeriesModel',
'api!series', 'api!series',
'Mixins/AsFilteredCollection',
'Mixins/AsPersistedStateCollection', 'Mixins/AsPersistedStateCollection',
'moment' 'moment'
], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsPersistedStateCollection, Moment) { ], function (_, Backbone, PageableCollection, SeriesModel, SeriesData, AsFilteredCollection, AsPersistedStateCollection, Moment) {
var Collection = PageableCollection.extend({ var Collection = PageableCollection.extend({
url : window.NzbDrone.ApiRoot + '/series', url : window.NzbDrone.ApiRoot + '/series',
model: SeriesModel, model: SeriesModel,
@ -47,6 +48,14 @@ define(
return proxy.save(); return proxy.save();
}, },
// Filter Modes
filterModes: {
'all' : [null, null],
'continuing' : ['status', 'continuing'],
'ended' : ['status', 'ended'],
'monitored' : ['monitored', true]
},
//Sorters //Sorters
nextAiring: function (model, attr) { nextAiring: function (model, attr) {
var nextAiring = model.get(attr); var nextAiring = model.get(attr);
@ -59,9 +68,9 @@ define(
} }
}); });
var MixedIn = AsPersistedStateCollection.call(Collection); var FilteredCollection = AsFilteredCollection.call(Collection);
var collection = new MixedIn(SeriesData); var MixedIn = AsPersistedStateCollection.call(FilteredCollection);
collection.initialSort(); var collection = new MixedIn(SeriesData, { full: true });
return collection; return collection;
}); });

@ -9,6 +9,10 @@ define(
template : 'Shared/Toolbar/ButtonTemplate', template : 'Shared/Toolbar/ButtonTemplate',
className: 'btn', className: 'btn',
ui: {
icon: 'i'
},
events: { events: {
'click': 'onClick' 'click': 'onClick'
}, },
@ -49,7 +53,7 @@ define(
var callback = this.model.get('callback'); var callback = this.model.get('callback');
if (callback) { if (callback) {
callback.call(this.model.ownerContext); callback.call(this.model.ownerContext, this);
} }
} }
}); });

@ -12,11 +12,9 @@ define(
return Marionette.Layout.extend({ return Marionette.Layout.extend({
template: 'Shared/Toolbar/ToolbarLayoutTemplate', template: 'Shared/Toolbar/ToolbarLayoutTemplate',
regions: { ui: {
left_1 : '.x-toolbar-left-1', left_x : '.x-toolbar-left',
left_2 : '.x-toolbar-left-2', right_x: '.x-toolbar-right'
right_1: '.x-toolbar-right-1',
right_2: '.x-toolbar-right-2'
}, },
initialize: function (options) { initialize: function (options) {
@ -97,8 +95,17 @@ define(
break; break;
} }
} }
this[position + '_' + (index + 1).toString()].show(buttonGroupView); var regionId = position + "_" + (index + 1);
var region = this[regionId];
if (!region) {
var regionClassName = "x-toolbar-" + position + "-" + (index + 1);
this.ui[position + '_x'].append('<div class="toolbar-group '+regionClassName+'" />\r\n');
region = this.addRegion(regionId, "." + regionClassName);
}
region.show(buttonGroupView);
} }
}); });
}); });

@ -1,8 +1,2 @@
<div class="pull-left page-toolbar"> <div class="pull-left page-toolbar x-toolbar-left" />
<div class="toolbar-group x-toolbar-left-1"/> <div class="pull-right page-toolbar x-toolbar-right" />
<div class="toolbar-group x-toolbar-left-2"/>
</div>
<div class="pull-right page-toolbar">
<div class="toolbar-group x-toolbar-right-1"/>
<div class="toolbar-group x-toolbar-right-2"/>
</div>

@ -4,9 +4,10 @@ define(
[ [
'backbone.pageable', 'backbone.pageable',
'System/Logs/LogsModel', 'System/Logs/LogsModel',
'Mixins/AsFilteredCollection',
'Mixins/AsPersistedStateCollection' 'Mixins/AsPersistedStateCollection'
], ],
function (PagableCollection, LogsModel, AsPersistedStateCollection) { function (PagableCollection, LogsModel, AsFilteredCollection, AsPersistedStateCollection) {
var collection = PagableCollection.extend({ var collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/log', url : window.NzbDrone.ApiRoot + '/log',
model: LogsModel, model: LogsModel,
@ -30,6 +31,14 @@ define(
} }
}, },
// Filter Modes
filterModes: {
'all' : [null, null],
'info' : ['level', 'Info'],
'warn' : ['level', 'Warn'],
'error' : ['level', 'Error']
},
parseState: function (resp, queryParams, state) { parseState: function (resp, queryParams, state) {
return {totalRecords: resp.totalRecords}; return {totalRecords: resp.totalRecords};
}, },
@ -43,5 +52,7 @@ define(
} }
}); });
return AsPersistedStateCollection.call(collection); collection = AsFilteredCollection.apply(collection);
return AsPersistedStateCollection.apply(collection);
}); });

@ -66,7 +66,6 @@ define(
onRender: function () { onRender: function () {
this.grid.show(new LoadingView()); this.grid.show(new LoadingView());
this.collection.fetch();
}, },
onShow: function () { onShow: function () {
@ -88,6 +87,44 @@ define(
}, },
_showToolbar: function () { _showToolbar: function () {
var filterButtons = {
type : 'radio',
storeState : true,
menuKey : 'logs.filterMode',
defaultAction: 'all',
items :
[
{
key : 'all',
title : '',
tooltip : 'All',
icon : 'icon-circle-blank',
callback : this._setFilter
},
{
key : 'info',
title : '',
tooltip : 'Info',
icon : 'icon-info',
callback : this._setFilter
},
{
key : 'warn',
title : '',
tooltip : 'Warn',
icon : 'icon-warn',
callback : this._setFilter
},
{
key : 'error',
title : '',
tooltip : 'Error',
icon : 'icon-error',
callback : this._setFilter
}
]
};
var rightSideButtons = { var rightSideButtons = {
type : 'default', type : 'default',
storeState: false, storeState: false,
@ -111,6 +148,7 @@ define(
this.toolbar.show(new ToolbarLayout({ this.toolbar.show(new ToolbarLayout({
right : right :
[ [
filterButtons,
rightSideButtons rightSideButtons
], ],
context: this context: this
@ -125,6 +163,19 @@ define(
buttonContext.ui.icon.spinForPromise(promise); buttonContext.ui.icon.spinForPromise(promise);
} }
}, },
_setFilter: function(buttonContext) {
var mode = buttonContext.model.get('key');
this.collection.setFilterMode(mode, { reset: false });
this.collection.state.currentPage = 1;
var promise = this.collection.fetch({ reset: true });
if (buttonContext) {
buttonContext.ui.icon.spinForPromise(promise);
}
},
_commandComplete: function (options) { _commandComplete: function (options) {
if (options.command.get('name') === 'clearlog') { if (options.command.get('name') === 'clearlog') {

Loading…
Cancel
Save