diff --git a/src/NzbDrone.Api/Queue/QueueActionModule.cs b/src/NzbDrone.Api/Queue/QueueActionModule.cs index 8b0d7621e..1b23c4a7a 100644 --- a/src/NzbDrone.Api/Queue/QueueActionModule.cs +++ b/src/NzbDrone.Api/Queue/QueueActionModule.cs @@ -1,4 +1,5 @@ -using Nancy; +using System; +using Nancy; using Nancy.Responses; using NzbDrone.Api.Extensions; using NzbDrone.Api.REST; @@ -14,6 +15,7 @@ namespace NzbDrone.Api.Queue private readonly IQueueService _queueService; private readonly ITrackedDownloadService _trackedDownloadService; private readonly ICompletedDownloadService _completedDownloadService; + private readonly IFailedDownloadService _failedDownloadService; private readonly IProvideDownloadClient _downloadClientProvider; private readonly IPendingReleaseService _pendingReleaseService; private readonly IDownloadService _downloadService; @@ -21,6 +23,7 @@ namespace NzbDrone.Api.Queue public QueueActionModule(IQueueService queueService, ITrackedDownloadService trackedDownloadService, ICompletedDownloadService completedDownloadService, + IFailedDownloadService failedDownloadService, IProvideDownloadClient downloadClientProvider, IPendingReleaseService pendingReleaseService, IDownloadService downloadService) @@ -28,6 +31,7 @@ namespace NzbDrone.Api.Queue _queueService = queueService; _trackedDownloadService = trackedDownloadService; _completedDownloadService = completedDownloadService; + _failedDownloadService = failedDownloadService; _downloadClientProvider = downloadClientProvider; _pendingReleaseService = pendingReleaseService; _downloadService = downloadService; @@ -39,6 +43,14 @@ namespace NzbDrone.Api.Queue private Response Remove(int id) { + var blacklist = false; + var blacklistQuery = Request.Query.blacklist; + + if (blacklistQuery.HasValue) + { + blacklist = Convert.ToBoolean(blacklistQuery.Value); + } + var pendingRelease = _pendingReleaseService.FindPendingQueueItem(id); if (pendingRelease != null) @@ -64,6 +76,11 @@ namespace NzbDrone.Api.Queue downloadClient.RemoveItem(trackedDownload.DownloadItem.DownloadId, true); + if (blacklist) + { + _failedDownloadService.MarkAsFailed(trackedDownload.DownloadItem.DownloadId); + } + return new object().AsResponse(); } diff --git a/src/NzbDrone.Core/Download/FailedDownloadService.cs b/src/NzbDrone.Core/Download/FailedDownloadService.cs index 898345f46..557e849a7 100644 --- a/src/NzbDrone.Core/Download/FailedDownloadService.cs +++ b/src/NzbDrone.Core/Download/FailedDownloadService.cs @@ -10,6 +10,7 @@ namespace NzbDrone.Core.Download public interface IFailedDownloadService { void MarkAsFailed(int historyId); + void MarkAsFailed(string downloadId); void Process(TrackedDownload trackedDownload); } @@ -41,6 +42,16 @@ namespace NzbDrone.Core.Download } } + public void MarkAsFailed(string downloadId) + { + var history = _historyService.Find(downloadId, HistoryEventType.Grabbed); + + if (history.Any()) + { + PublishDownloadFailedEvent(history, "Manually marked as failed"); + } + } + public void Process(TrackedDownload trackedDownload) { var grabbedItems = _historyService.Find(trackedDownload.DownloadItem.DownloadId, HistoryEventType.Grabbed) diff --git a/src/UI/Activity/Queue/QueueActionsCell.js b/src/UI/Activity/Queue/QueueActionsCell.js index 4c5c4b7cc..d97c4cf83 100644 --- a/src/UI/Activity/Queue/QueueActionsCell.js +++ b/src/UI/Activity/Queue/QueueActionsCell.js @@ -4,10 +4,13 @@ define( [ 'jquery', 'marionette', - 'Cells/NzbDroneCell' - ], function ($, Marionette, NzbDroneCell) { - return NzbDroneCell.extend({ + 'Cells/TemplatedCell', + 'Activity/Queue/RemoveFromQueueView', + 'vent' + ], function ($, Marionette, TemplatedCell, RemoveFromQueueView, vent) { + return TemplatedCell.extend({ + template : 'Activity/Queue/QueueActionsCellTemplate', className : 'queue-actions-cell', events: { @@ -21,48 +24,11 @@ define( grab : '.x-grab' }, - render: function () { - this.$el.empty(); - - if (this.cellValue) { - var status = this.cellValue.get('status').toLowerCase(); - var trackedDownloadStatus = this.cellValue.has('trackedDownloadStatus') ? this.cellValue.get('trackedDownloadStatus').toLowerCase() : 'ok'; - var icon = ''; - var title = ''; - - if (status === 'completed' && trackedDownloadStatus === 'warning') { - icon = 'icon-inbox x-import'; - title = 'Force import'; - } - - if (status === 'pending') { - icon = 'icon-download-alt x-grab'; - title = 'Add to download queue (Override Delay Profile)'; - } - - //TODO: Show manual import if its completed or option to blacklist - //if (trackedDownloadStatus === 'error') { - // if (status === 'completed') { - // icon = 'icon-nd-import-failed'; - // title = 'Import failed: ' + itemTitle; - // } - //TODO: What do we show when waiting for retry to take place? - - // else { - // icon = 'icon-nd-download-failed'; - // title = 'Download failed'; - // } - //} - - this.$el.html(''.format(icon, title) + - ''); - } + _remove : function () { - return this; - }, + var showBlacklist = this.model.get('status') !== 'Pending'; - _remove : function () { - this.model.destroy(); + vent.trigger(vent.Commands.OpenModalCommand, new RemoveFromQueueView({ model: this.model, showBlacklist: showBlacklist })); }, _import : function () { diff --git a/src/UI/Activity/Queue/QueueActionsCellTemplate.hbs b/src/UI/Activity/Queue/QueueActionsCellTemplate.hbs new file mode 100644 index 000000000..9ea2a40c9 --- /dev/null +++ b/src/UI/Activity/Queue/QueueActionsCellTemplate.hbs @@ -0,0 +1,12 @@ +{{#if_eq status compare="Completed"}} + {{#if_eq trackedDownloadStatus compare="Warning"}} + + {{/if_eq}} +{{/if_eq}} + +{{#if_eq status compare="Pending"}} + + +{{else}} + +{{/if_eq}} diff --git a/src/UI/Activity/Queue/RemoveFromQueueView.js b/src/UI/Activity/Queue/RemoveFromQueueView.js new file mode 100644 index 000000000..be691d16d --- /dev/null +++ b/src/UI/Activity/Queue/RemoveFromQueueView.js @@ -0,0 +1,39 @@ +'use strict'; +define( + [ + 'vent', + 'marionette' + ], function (vent, Marionette) { + + return Marionette.ItemView.extend({ + template: 'Activity/Queue/RemoveFromQueueViewTemplate', + + events: { + 'click .x-confirm-remove' : 'removeItem' + }, + + ui: { + blacklist : '.x-blacklist', + indicator : '.x-indicator' + }, + + initialize: function (options) { + this.templateHelpers = { + showBlacklist: options.showBlacklist + }; + }, + + removeItem: function () { + var blacklist = this.ui.blacklist.prop('checked'); + + this.ui.indicator.show(); + + this.model.destroy({ + data: { 'blacklist': blacklist }, + wait: true + }).done(function () { + vent.trigger(vent.Commands.CloseModalCommand); + }); + } + }); + }); diff --git a/src/UI/Activity/Queue/RemoveFromQueueViewTemplate.hbs b/src/UI/Activity/Queue/RemoveFromQueueViewTemplate.hbs new file mode 100644 index 000000000..46d6f643c --- /dev/null +++ b/src/UI/Activity/Queue/RemoveFromQueueViewTemplate.hbs @@ -0,0 +1,49 @@ +
diff --git a/src/UI/Activity/activity.less b/src/UI/Activity/activity.less index 5bd498bff..7bf72d6f7 100644 --- a/src/UI/Activity/activity.less +++ b/src/UI/Activity/activity.less @@ -9,3 +9,9 @@ width : 80px; } } + +.remove-from-queue-modal { + .form-horizontal { + margin-top : 20px; + } +} diff --git a/src/UI/Cells/cells.less b/src/UI/Cells/cells.less index e23d2bf00..189470a19 100644 --- a/src/UI/Cells/cells.less +++ b/src/UI/Cells/cells.less @@ -156,12 +156,12 @@ td.episode-status-cell, td.quality-cell, td.history-quality-cell, td.progress-ce } .queue-actions-cell { - width : 55px; + width : 70px; text-align : right !important; i { - margin-left : 3px; - margin-right : 3px; + margin-left : 1px; + margin-right : 1px; } } diff --git a/src/UI/Content/icons.less b/src/UI/Content/icons.less index 79e8dd76e..5031edd34 100644 --- a/src/UI/Content/icons.less +++ b/src/UI/Content/icons.less @@ -60,6 +60,11 @@ color : @brand-danger; } +.icon-nd-blacklist:before { + .icon(@ban-circle); + color : @brand-danger; +} + .icon-nd-spinner:before { .icon(@spinner); .icon-spin;