mirror of
https://github.com/Sonarr/Sonarr.git
synced 2024-12-16 11:37:58 +02:00
Episode Activity added
New: Activity tab added to Episode Details
This commit is contained in:
parent
d0d65db4f2
commit
c0b7612053
16
Gruntfile.js
16
Gruntfile.js
@ -169,35 +169,35 @@ module.exports = function (grunt) {
|
||||
tasks: ['handlebars']
|
||||
},
|
||||
copyIndex : {
|
||||
files: '<%= copy.index.src %>',
|
||||
files: '<%= copy.index.cwd %><%= copy.index.src %>',
|
||||
tasks: ['copy:index']
|
||||
},
|
||||
copyScripts: {
|
||||
files: '<%= copy.scripts.src %>',
|
||||
files: '<%= copy.scripts.cwd %><%= copy.scripts.src %>',
|
||||
tasks: ['copy:scripts']
|
||||
},
|
||||
copyStyles : {
|
||||
files: '<%= copy.styles.src %>',
|
||||
files: '<%= copy.styles.cwd %><%= copy.styles.src %>',
|
||||
tasks: ['copy:styles']
|
||||
},
|
||||
copyImages : {
|
||||
files: '<%= copy.images.src %>',
|
||||
files: '<%= copy.images.cwd %><%= copy.images.src %>',
|
||||
tasks: ['copy:images']
|
||||
},
|
||||
copyJpg : {
|
||||
files: '<%= copy.jpg.src %>',
|
||||
files: '<%= copy.jpg.cwd %><%= copy.jpg.src %>',
|
||||
tasks: ['copy:jpg']
|
||||
},
|
||||
copyIcon : {
|
||||
files: '<%= copy.icon.src %>',
|
||||
files: '<%= copy.icon.cwd %><%= copy.icon.src %>',
|
||||
tasks: ['copy:icon']
|
||||
},
|
||||
copyFontAwesome : {
|
||||
files: '<%= copy.fontAwesome.src %>',
|
||||
files: '<%= copy.fontAwesome.cwd %><%= copy.fontAwesome.src %>',
|
||||
tasks: ['copy:fontAwesome']
|
||||
},
|
||||
copyFonts : {
|
||||
files: '<%= copy.fonts.src %>',
|
||||
files: '<%= copy.fonts.cwd %><%= copy.fonts.src %>',
|
||||
tasks: ['copy:fonts']
|
||||
}
|
||||
}
|
||||
|
39
src/NzbDrone.Api/Episodes/EpisodeActivityModule.cs
Normal file
39
src/NzbDrone.Api/Episodes/EpisodeActivityModule.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
@ -91,6 +91,7 @@
|
||||
<Compile Include="EpisodeFiles\EpisodeFileResource.cs" />
|
||||
<Compile Include="Directories\DirectoryLookupService.cs" />
|
||||
<Compile Include="Directories\DirectoryModule.cs" />
|
||||
<Compile Include="Episodes\EpisodeActivityModule.cs" />
|
||||
<Compile Include="Episodes\EpisodeModule.cs" />
|
||||
<Compile Include="Episodes\EpisodeResource.cs" />
|
||||
<Compile Include="Extensions\Pipelines\CacheHeaderPipeline.cs" />
|
||||
|
@ -12,6 +12,7 @@ public interface IHistoryRepository : IBasicRepository<History>
|
||||
{
|
||||
void Trim();
|
||||
List<QualityModel> GetEpisodeHistory(int episodeId);
|
||||
List<History> ByEpisode(int episodeId);
|
||||
}
|
||||
|
||||
public class HistoryRepository : BasicRepository<History>, IHistoryRepository
|
||||
@ -37,6 +38,11 @@ public List<QualityModel> GetEpisodeHistory(int episodeId)
|
||||
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)
|
||||
{
|
||||
var pagingQuery = Query.Join<History, Series>(JoinType.Inner, h => h.Series, (h, s) => h.SeriesId == s.Id)
|
||||
|
@ -17,6 +17,7 @@ public interface IHistoryService
|
||||
void Trim();
|
||||
QualityModel GetBestQualityInHistory(int episodeId);
|
||||
PagingSpec<History> Paged(PagingSpec<History> pagingSpec);
|
||||
List<History> ByEpisode(int episodeId);
|
||||
}
|
||||
|
||||
public class HistoryService : IHistoryService, IHandle<EpisodeGrabbedEvent>, IHandle<EpisodeImportedEvent>
|
||||
@ -40,6 +41,11 @@ public PagingSpec<History> Paged(PagingSpec<History> pagingSpec)
|
||||
return _historyRepository.GetPaged(pagingSpec);
|
||||
}
|
||||
|
||||
public List<History> ByEpisode(int episodeId)
|
||||
{
|
||||
return _historyRepository.ByEpisode(episodeId);
|
||||
}
|
||||
|
||||
public void Purge()
|
||||
{
|
||||
_historyRepository.Purge();
|
||||
|
@ -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;
|
31
src/UI/Episode/Activity/EpisodeActivityCollection.js
Normal file
31
src/UI/Episode/Activity/EpisodeActivityCollection.js
Normal 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);
|
||||
}
|
||||
});
|
||||
});
|
72
src/UI/Episode/Activity/EpisodeActivityLayout.js
Normal file
72
src/UI/Episode/Activity/EpisodeActivityLayout.js
Normal 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'
|
||||
}));
|
||||
}
|
||||
});
|
||||
});
|
@ -0,0 +1 @@
|
||||
<div class="activity-table"></div>
|
9
src/UI/Episode/Activity/EpisodeActivityModel.js
Normal file
9
src/UI/Episode/Activity/EpisodeActivityModel.js
Normal file
@ -0,0 +1,9 @@
|
||||
'use strict';
|
||||
define(
|
||||
[
|
||||
'backbone'
|
||||
], function (Backbone) {
|
||||
return Backbone.Model.extend({
|
||||
|
||||
});
|
||||
});
|
@ -4,8 +4,9 @@ define(
|
||||
'marionette',
|
||||
'Episode/Summary/EpisodeSummaryLayout',
|
||||
'Episode/Search/EpisodeSearchLayout',
|
||||
'Episode/Activity/EpisodeActivityLayout',
|
||||
'Series/SeriesCollection'
|
||||
], function (Marionette, SummaryLayout, SearchLayout, SeriesCollection) {
|
||||
], function (Marionette, SummaryLayout, SearchLayout, EpisodeActivityLayout, SeriesCollection) {
|
||||
|
||||
return Marionette.Layout.extend({
|
||||
template: 'Episode/EpisodeDetailsLayoutTemplate',
|
||||
@ -38,7 +39,7 @@ define(
|
||||
|
||||
this.series = SeriesCollection.find({ id: this.model.get('seriesId') });
|
||||
this.templateHelpers.series = this.series.toJSON();
|
||||
this.openingTab = options.openingTab || 'summary'
|
||||
this.openingTab = options.openingTab || 'summary';
|
||||
},
|
||||
|
||||
onShow: function () {
|
||||
@ -71,6 +72,7 @@ define(
|
||||
}
|
||||
|
||||
this.ui.activity.tab('show');
|
||||
this.activity.show(new EpisodeActivityLayout({model: this.model, series: this.series}));
|
||||
},
|
||||
|
||||
_showSearch: function (e) {
|
||||
|
@ -15,12 +15,12 @@
|
||||
<div class="modal-body">
|
||||
<ul class="nav nav-tabs" id="myTab">
|
||||
<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>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<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>
|
||||
</div>
|
||||
|
@ -58,7 +58,7 @@ define(
|
||||
if (App.reqres.hasHandler(App.Reqres.GetEpisodeFileById)) {
|
||||
var episodeFile = App.request(App.Reqres.GetEpisodeFileById, episodeFileId);
|
||||
var episodeFileCollection = new EpisodeFileCollection(episodeFile, { seriesId: this.model.get('seriesId') });
|
||||
this._showTable(episodeFileCollection)
|
||||
this._showTable(episodeFileCollection);
|
||||
}
|
||||
|
||||
else {
|
||||
|
@ -4,7 +4,7 @@ define(
|
||||
'marionette',
|
||||
'backgrid',
|
||||
'History/HistoryCollection',
|
||||
'History/Table/EventTypeCell',
|
||||
'Cells/EventTypeCell',
|
||||
'Cells/SeriesTitleCell',
|
||||
'Cells/EpisodeNumberCell',
|
||||
'Cells/EpisodeTitleCell',
|
||||
|
Loading…
Reference in New Issue
Block a user