From 6ca17942f07223f737ffaf48bfc4127bfc0cfc09 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 5 Aug 2013 02:09:41 -0700 Subject: [PATCH] Added season pass for toggling monitored status of seasons Linked from missing --- NzbDrone.Api/Seasons/SeasonModule.cs | 17 +++- NzbDrone.Core/Tv/SeasonService.cs | Bin 6889 -> 8219 bytes UI/Controller.js | 14 +-- UI/Missing/MissingLayout.js | 28 +++++- UI/Router.js | 1 + UI/SeasonPass/Layout.js | 39 ++++++++ UI/SeasonPass/LayoutTemplate.html | 11 +++ UI/SeasonPass/SeriesCollectionView.js | 26 ++++++ UI/SeasonPass/SeriesLayout.js | 117 ++++++++++++++++++++++++ UI/SeasonPass/SeriesLayoutTemplate.html | 32 +++++++ UI/Series/SeasonCollection.js | 27 +++--- UI/Series/series.less | 26 ++++++ 12 files changed, 316 insertions(+), 22 deletions(-) create mode 100644 UI/SeasonPass/Layout.js create mode 100644 UI/SeasonPass/LayoutTemplate.html create mode 100644 UI/SeasonPass/SeriesCollectionView.js create mode 100644 UI/SeasonPass/SeriesLayout.js create mode 100644 UI/SeasonPass/SeriesLayoutTemplate.html diff --git a/NzbDrone.Api/Seasons/SeasonModule.cs b/NzbDrone.Api/Seasons/SeasonModule.cs index 773faf85f..cd68b2881 100644 --- a/NzbDrone.Api/Seasons/SeasonModule.cs +++ b/NzbDrone.Api/Seasons/SeasonModule.cs @@ -14,13 +14,20 @@ namespace NzbDrone.Api.Seasons GetResourceAll = GetSeasons; UpdateResource = SetMonitored; + + Post["/pass"] = x => SetSeasonPass(); } private List GetSeasons() { var seriesId = Request.Query.SeriesId; - return ToListResource(() => _seasonService.GetSeasonsBySeries(seriesId)); + if (seriesId.HasValue) + { + return ToListResource(() => _seasonService.GetSeasonsBySeries(seriesId)); + } + + return ToListResource(() => _seasonService.GetAllSeasons()); } private SeasonResource SetMonitored(SeasonResource seasonResource) @@ -29,5 +36,13 @@ namespace NzbDrone.Api.Seasons return seasonResource; } + + private List SetSeasonPass() + { + var seriesId = Request.Form.SeriesId; + var seasonNumber = Request.Form.SeasonNumber; + + return ToListResource(() => _seasonService.SetSeasonPass(seriesId, seasonNumber)); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Tv/SeasonService.cs b/NzbDrone.Core/Tv/SeasonService.cs index a7ca88c4b1f839407ad5e2a6455b499c78682e0d..95eff2c7606003abb0b84a7c780426497aea019d 100644 GIT binary patch delta 554 zcma)3O-lkn7)DrKU0cJn4>f5rsI`N1iJ(*ziU>l2mAbmgtPR+%?2HJCKcJiP9y{~{ z3Oaa>>X&p5x=Z zi_w1TLDezSu|aL?#GthQwgL%H0oFXxV6k2o1l0z*=S6~&JR3hIlw}2+M}Mqge;n?; z{(RXns#r^Lo)N2tnhh>>BaoYcOxr=7tuCU>a7KKKunR;-ie1jYqZFS@@2Lu!da45N zfd#k=E_x`O`q#rkkBBvPQt0_po5Vz#U@{`I)Vw^$4$9}oGEt}bcUffvI#NYqP7?zP zM4_TcFq9$!SPewrNLEANE#NxE6O-38cs=bJBitr;MdwhI=b`OghR@&<+i{Cng&fS9&SczYIR-i3P2$%{4l$d$8@LC#^2Jn+Y3WSacC{Kj$#FQ7lYMw delta 35 tcmV+;0NnqZK +
+
Season Pass allows you to quickly change the monitored status of seasons for all your series in one place
+
+ + +
+
+
+
+
\ No newline at end of file diff --git a/UI/SeasonPass/SeriesCollectionView.js b/UI/SeasonPass/SeriesCollectionView.js new file mode 100644 index 000000000..48cf5c39e --- /dev/null +++ b/UI/SeasonPass/SeriesCollectionView.js @@ -0,0 +1,26 @@ +'use strict'; +define( + [ + 'marionette', + 'SeasonPass/SeriesLayout' + ], function (Marionette, SeriesLayout) { + return Marionette.CollectionView.extend({ + + itemView: SeriesLayout, + + initialize: function (options) { + + if (!options.seasonCollection) { + throw 'seasonCollection is needed'; + } + + this.seasonCollection = options.seasonCollection; + }, + + itemViewOptions: function () { + return { + seasonCollection: this.seasonCollection + }; + } + }); + }); diff --git a/UI/SeasonPass/SeriesLayout.js b/UI/SeasonPass/SeriesLayout.js new file mode 100644 index 000000000..f0382adfd --- /dev/null +++ b/UI/SeasonPass/SeriesLayout.js @@ -0,0 +1,117 @@ +'use strict'; +define( + [ + 'marionette', + 'backgrid', + 'Series/SeasonCollection', + 'Cells/ToggleCell', + 'Shared/Actioneer' + ], function (Marionette, Backgrid, SeasonCollection, ToggleCell, Actioneer) { + return Marionette.Layout.extend({ + template: 'SeasonPass/SeriesLayoutTemplate', + + ui: { + seasonSelect: '.x-season-select', + expander : '.x-expander', + seasonGrid : '.x-season-grid' + }, + + events: { + 'change .x-season-select': '_seasonSelected', + 'click .x-expander' : '_expand' + }, + + regions: { + seasonGrid: '.x-season-grid' + }, + + columns: + [ + { + name : 'monitored', + label : '', + cell : ToggleCell, + trueClass : 'icon-bookmark', + falseClass: 'icon-bookmark-empty', + tooltip : 'Toggle monitored status', + sortable : false + }, + { + name : 'seasonNumber', + label: 'Season', + cell : Backgrid.IntegerCell.extend({ + className: 'season-number-cell' + }) + } + ], + + initialize: function (options) { + this.seasonCollection = options.seasonCollection.bySeries(this.model.get('id')); + this.model.set('seasons', this.seasonCollection); + this.expanded = false; + }, + + onRender: function () { + this.seasonGrid.show(new Backgrid.Grid({ + columns : this.columns, + collection: this.seasonCollection, + className : 'table table-condensed season-grid span5' + })); + + if (!this.expanded) { + this.seasonGrid.$el.hide(); + } + + this._setExpanderIcon(); + }, + + _seasonSelected: function () { + var self = this; + var seasonNumber = parseInt(this.ui.seasonSelect.val()); + + if (seasonNumber == -1) { + return; + } + + var promise = $.ajax({ + url: this.seasonCollection.url + '/pass', + type: 'POST', + data: { + seriesId: this.model.get('id'), + seasonNumber: seasonNumber + } + }); + + promise.done(function (data) { + self.seasonCollection = new SeasonCollection(data); + self.render(); + }); + }, + + _expand: function () { + if (this.expanded) { + this.ui.seasonGrid.slideUp(); + this.expanded = false; + } + + else { + this.ui.seasonGrid.slideDown(); + this.expanded = true; + } + + this._setExpanderIcon(); + }, + + _setExpanderIcon: function () { + if (this.expanded) { + this.ui.expander.removeClass('icon-chevron-right'); + this.ui.expander.addClass('icon-chevron-down'); + } + + else { + this.ui.expander.removeClass('icon-chevron-down'); + this.ui.expander.addClass('icon-chevron-right'); + } + } + }); + }); diff --git a/UI/SeasonPass/SeriesLayoutTemplate.html b/UI/SeasonPass/SeriesLayoutTemplate.html new file mode 100644 index 000000000..a9d4ac7e2 --- /dev/null +++ b/UI/SeasonPass/SeriesLayoutTemplate.html @@ -0,0 +1,32 @@ +
+
+
+ + + + + {{title}} + + + + + + +
+
+ +
+
+
+
+
+
diff --git a/UI/Series/SeasonCollection.js b/UI/Series/SeasonCollection.js index a1abbc898..68e312ff1 100644 --- a/UI/Series/SeasonCollection.js +++ b/UI/Series/SeasonCollection.js @@ -1,24 +1,25 @@ 'use strict'; define( [ - 'Series/SeasonModel', - 'backbone.pageable' - ], function (SeasonModel, PageAbleCollection) { - return PageAbleCollection.extend({ + 'backbone', + 'Series/SeasonModel' + ], function (Backbone, SeasonModel) { + return Backbone.Collection.extend({ url : window.ApiRoot + '/season', model: SeasonModel, - mode: 'client', - - state: { - sortKey : 'seasonNumber', - order : 1, - pageSize: 1000000 + comparator: function (season) { + return -season.get('seasonNumber'); }, - queryParams: { - sortKey: null, - order : null + bySeries: function (series) { + var filtered = this.filter(function (season) { + return season.get('seriesId') === series; + }); + + var SeasonCollection = require('Series/SeasonCollection'); + + return new SeasonCollection(filtered); } }); }); diff --git a/UI/Series/series.less b/UI/Series/series.less index 82e37be67..061fb3bce 100644 --- a/UI/Series/series.less +++ b/UI/Series/series.less @@ -246,4 +246,30 @@ .series-legend { padding-top: 5px; +} + +.seasonpass-series { + .card; + margin : 20px 0px; + + .title { + font-weight: 300; + font-size: 24px; + line-height: 30px; + margin-left: 5px; + } + + .season-select { + margin-bottom: 0px; + } + + .expander { + .clickable; + line-height: 30px; + margin-left: 8px; + } + + .season-grid { + margin-top: 10px; + } } \ No newline at end of file