1
0
mirror of https://github.com/Radarr/Radarr.git synced 2024-11-04 10:02:40 +01:00

Episode Activity added

New: Activity tab added to Episode Details
This commit is contained in:
Mark McDowall 2013-10-03 23:01:02 -07:00
parent d0d65db4f2
commit c0b7612053
14 changed files with 182 additions and 15 deletions

View File

@ -169,35 +169,35 @@ module.exports = function (grunt) {
tasks: ['handlebars'] tasks: ['handlebars']
}, },
copyIndex : { copyIndex : {
files: '<%= copy.index.src %>', files: '<%= copy.index.cwd %><%= copy.index.src %>',
tasks: ['copy:index'] tasks: ['copy:index']
}, },
copyScripts: { copyScripts: {
files: '<%= copy.scripts.src %>', files: '<%= copy.scripts.cwd %><%= copy.scripts.src %>',
tasks: ['copy:scripts'] tasks: ['copy:scripts']
}, },
copyStyles : { copyStyles : {
files: '<%= copy.styles.src %>', files: '<%= copy.styles.cwd %><%= copy.styles.src %>',
tasks: ['copy:styles'] tasks: ['copy:styles']
}, },
copyImages : { copyImages : {
files: '<%= copy.images.src %>', files: '<%= copy.images.cwd %><%= copy.images.src %>',
tasks: ['copy:images'] tasks: ['copy:images']
}, },
copyJpg : { copyJpg : {
files: '<%= copy.jpg.src %>', files: '<%= copy.jpg.cwd %><%= copy.jpg.src %>',
tasks: ['copy:jpg'] tasks: ['copy:jpg']
}, },
copyIcon : { copyIcon : {
files: '<%= copy.icon.src %>', files: '<%= copy.icon.cwd %><%= copy.icon.src %>',
tasks: ['copy:icon'] tasks: ['copy:icon']
}, },
copyFontAwesome : { copyFontAwesome : {
files: '<%= copy.fontAwesome.src %>', files: '<%= copy.fontAwesome.cwd %><%= copy.fontAwesome.src %>',
tasks: ['copy:fontAwesome'] tasks: ['copy:fontAwesome']
}, },
copyFonts : { copyFonts : {
files: '<%= copy.fonts.src %>', files: '<%= copy.fonts.cwd %><%= copy.fonts.src %>',
tasks: ['copy:fonts'] tasks: ['copy:fonts']
} }
} }

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using NzbDrone.Api.History;
using NzbDrone.Api.Mapping;
using NzbDrone.Api.REST;
using NzbDrone.Core.Datastore.Events;
using NzbDrone.Core.Download;
using NzbDrone.Core.History;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Tv;
namespace NzbDrone.Api.Episodes
{
public class EpisodeActivityModule : NzbDroneRestModule<HistoryResource>
{
private readonly IHistoryService _historyService;
public EpisodeActivityModule(IHistoryService historyService)
: base("episodes/activity")
{
_historyService = historyService;
GetResourceAll = GetActivity;
}
private List<HistoryResource> GetActivity()
{
var episodeId = (int?)Request.Query.EpisodeId;
if (episodeId == null)
{
throw new BadRequestException("episodeId is missing");
}
return ToListResource(() => _historyService.ByEpisode(episodeId.Value));
}
}
}

View File

@ -91,6 +91,7 @@
<Compile Include="EpisodeFiles\EpisodeFileResource.cs" /> <Compile Include="EpisodeFiles\EpisodeFileResource.cs" />
<Compile Include="Directories\DirectoryLookupService.cs" /> <Compile Include="Directories\DirectoryLookupService.cs" />
<Compile Include="Directories\DirectoryModule.cs" /> <Compile Include="Directories\DirectoryModule.cs" />
<Compile Include="Episodes\EpisodeActivityModule.cs" />
<Compile Include="Episodes\EpisodeModule.cs" /> <Compile Include="Episodes\EpisodeModule.cs" />
<Compile Include="Episodes\EpisodeResource.cs" /> <Compile Include="Episodes\EpisodeResource.cs" />
<Compile Include="Extensions\Pipelines\CacheHeaderPipeline.cs" /> <Compile Include="Extensions\Pipelines\CacheHeaderPipeline.cs" />

View File

@ -12,6 +12,7 @@ public interface IHistoryRepository : IBasicRepository<History>
{ {
void Trim(); void Trim();
List<QualityModel> GetEpisodeHistory(int episodeId); List<QualityModel> GetEpisodeHistory(int episodeId);
List<History> ByEpisode(int episodeId);
} }
public class HistoryRepository : BasicRepository<History>, IHistoryRepository public class HistoryRepository : BasicRepository<History>, IHistoryRepository
@ -37,6 +38,11 @@ public List<QualityModel> GetEpisodeHistory(int episodeId)
return history.Select(h => h.Quality).ToList(); return history.Select(h => h.Quality).ToList();
} }
public List<History> ByEpisode(int episodeId)
{
return Query.Where(h => h.EpisodeId == episodeId).ToList();
}
public override PagingSpec<History> GetPaged(PagingSpec<History> pagingSpec) public override PagingSpec<History> GetPaged(PagingSpec<History> pagingSpec)
{ {
var pagingQuery = Query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id) var pagingQuery = Query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id)

View File

@ -17,6 +17,7 @@ public interface IHistoryService
void Trim(); void Trim();
QualityModel GetBestQualityInHistory(int episodeId); QualityModel GetBestQualityInHistory(int episodeId);
PagingSpec<History> Paged(PagingSpec<History> pagingSpec); PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
List<History> ByEpisode(int episodeId);
} }
public class HistoryService : IHistoryService, IHandle<EpisodeGrabbedEvent>, IHandle<EpisodeImportedEvent> public class HistoryService : IHistoryService, IHandle<EpisodeGrabbedEvent>, IHandle<EpisodeImportedEvent>
@ -40,6 +41,11 @@ public PagingSpec<History> Paged(PagingSpec<History> pagingSpec)
return _historyRepository.GetPaged(pagingSpec); return _historyRepository.GetPaged(pagingSpec);
} }
public List<History> ByEpisode(int episodeId)
{
return _historyRepository.ByEpisode(episodeId);
}
public void Purge() public void Purge()
{ {
_historyRepository.Purge(); _historyRepository.Purge();

View File

@ -35,7 +35,7 @@ define(
} }
this.$el.html('<i class="{0}" title="{1}"/>'.format(icon, toolTip)); this.$el.html('<i class="{0}" title="{1}" data-placement="right"/>'.format(icon, toolTip));
} }
return this; return this;

View File

@ -0,0 +1,31 @@
'use strict';
define(
[
'backbone',
'Episode/Activity/EpisodeActivityModel'
], function (Backbone, EpisodeActivityModel) {
return Backbone.Collection.extend({
url : window.NzbDrone.ApiRoot + '/episodes/activity',
model: EpisodeActivityModel,
originalFetch: Backbone.Collection.prototype.fetch,
initialize: function (options) {
this.episodeId = options.episodeId;
},
fetch: function (options) {
if (!this.episodeId) {
throw 'episodeId is required';
}
if (!options) {
options = {};
}
options.data = { episodeId: this.episodeId };
return this.originalFetch.call(this, options);
}
});
});

View File

@ -0,0 +1,72 @@
'use strict';
define(
[
'app',
'marionette',
'backgrid',
'Episode/Activity/EpisodeActivityCollection',
'Cells/EventTypeCell',
'Cells/QualityCell',
'Cells/RelativeDateCell',
'Shared/LoadingView'
], function (App, Marionette, Backgrid, EpisodeActivityCollection, EventTypeCell, QualityCell, RelativeDateCell, LoadingView) {
return Marionette.Layout.extend({
template: 'Episode/Activity/EpisodeActivityLayoutTemplate',
regions: {
activityTable: '.activity-table'
},
columns:
[
{
name : 'eventType',
label : '',
cell : EventTypeCell,
cellValue: 'this'
},
{
name : 'sourceTitle',
label: 'Source Title',
cell : 'string'
},
{
name : 'quality',
label: 'Quality',
cell : QualityCell
},
{
name : 'date',
label: 'Date',
cell : RelativeDateCell
}
],
initialize: function (options) {
this.model = options.model;
this.series = options.series;
this.collection = new EpisodeActivityCollection({ episodeId: this.model.id });
},
onShow: function () {
var self = this;
this.activityTable.show(new LoadingView());
var promise = this.collection.fetch();
promise.done(function () {
self._showTable();
});
},
_showTable: function () {
this.activityTable.show(new Backgrid.Grid({
collection: this.collection,
columns : this.columns,
className : 'table table-hover table-condensed'
}));
}
});
});

View File

@ -0,0 +1 @@
<div class="activity-table"></div>

View File

@ -0,0 +1,9 @@
'use strict';
define(
[
'backbone'
], function (Backbone) {
return Backbone.Model.extend({
});
});

View File

@ -4,8 +4,9 @@ define(
'marionette', 'marionette',
'Episode/Summary/EpisodeSummaryLayout', 'Episode/Summary/EpisodeSummaryLayout',
'Episode/Search/EpisodeSearchLayout', 'Episode/Search/EpisodeSearchLayout',
'Episode/Activity/EpisodeActivityLayout',
'Series/SeriesCollection' 'Series/SeriesCollection'
], function (Marionette, SummaryLayout, SearchLayout, SeriesCollection) { ], function (Marionette, SummaryLayout, SearchLayout, EpisodeActivityLayout, SeriesCollection) {
return Marionette.Layout.extend({ return Marionette.Layout.extend({
template: 'Episode/EpisodeDetailsLayoutTemplate', template: 'Episode/EpisodeDetailsLayoutTemplate',
@ -38,7 +39,7 @@ define(
this.series = SeriesCollection.find({ id: this.model.get('seriesId') }); this.series = SeriesCollection.find({ id: this.model.get('seriesId') });
this.templateHelpers.series = this.series.toJSON(); this.templateHelpers.series = this.series.toJSON();
this.openingTab = options.openingTab || 'summary' this.openingTab = options.openingTab || 'summary';
}, },
onShow: function () { onShow: function () {
@ -71,6 +72,7 @@ define(
} }
this.ui.activity.tab('show'); this.ui.activity.tab('show');
this.activity.show(new EpisodeActivityLayout({model: this.model, series: this.series}));
}, },
_showSearch: function (e) { _showSearch: function (e) {

View File

@ -15,12 +15,12 @@
<div class="modal-body"> <div class="modal-body">
<ul class="nav nav-tabs" id="myTab"> <ul class="nav nav-tabs" id="myTab">
<li><a href="#episode-summary" class="x-episode-summary">Summary</a></li> <li><a href="#episode-summary" class="x-episode-summary">Summary</a></li>
<!-- <li><a href="#episode-activity" class="x-episode-activity">Activity</a></li>--> <li><a href="#episode-activity" class="x-episode-activity">Activity</a></li>
<li><a href="#episode-search" class="x-episode-search">Search</a></li> <li><a href="#episode-search" class="x-episode-search">Search</a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane" id="episode-summary"/> <div class="tab-pane" id="episode-summary"/>
<!--<div class="tab-pane" id="episode-activity"/>--> <div class="tab-pane" id="episode-activity"/>
<div class="tab-pane" id="episode-search"/> <div class="tab-pane" id="episode-search"/>
</div> </div>
</div> </div>

View File

@ -58,7 +58,7 @@ define(
if (App.reqres.hasHandler(App.Reqres.GetEpisodeFileById)) { if (App.reqres.hasHandler(App.Reqres.GetEpisodeFileById)) {
var episodeFile = App.request(App.Reqres.GetEpisodeFileById, episodeFileId); var episodeFile = App.request(App.Reqres.GetEpisodeFileById, episodeFileId);
var episodeFileCollection = new EpisodeFileCollection(episodeFile, { seriesId: this.model.get('seriesId') }); var episodeFileCollection = new EpisodeFileCollection(episodeFile, { seriesId: this.model.get('seriesId') });
this._showTable(episodeFileCollection) this._showTable(episodeFileCollection);
} }
else { else {

View File

@ -4,7 +4,7 @@ define(
'marionette', 'marionette',
'backgrid', 'backgrid',
'History/HistoryCollection', 'History/HistoryCollection',
'History/Table/EventTypeCell', 'Cells/EventTypeCell',
'Cells/SeriesTitleCell', 'Cells/SeriesTitleCell',
'Cells/EpisodeNumberCell', 'Cells/EpisodeNumberCell',
'Cells/EpisodeTitleCell', 'Cells/EpisodeTitleCell',