New: Scheduled tasks shwon in UI under System
This commit is contained in:
parent
879035b28a
commit
2b0ddb6131
|
@ -207,6 +207,8 @@
|
||||||
<Compile Include="Series\SeriesResource.cs" />
|
<Compile Include="Series\SeriesResource.cs" />
|
||||||
<Compile Include="System\Backup\BackupModule.cs" />
|
<Compile Include="System\Backup\BackupModule.cs" />
|
||||||
<Compile Include="System\Backup\BackupResource.cs" />
|
<Compile Include="System\Backup\BackupResource.cs" />
|
||||||
|
<Compile Include="System\Tasks\TaskModule.cs" />
|
||||||
|
<Compile Include="System\Tasks\TaskResource.cs" />
|
||||||
<Compile Include="System\SystemModule.cs" />
|
<Compile Include="System\SystemModule.cs" />
|
||||||
<Compile Include="TinyIoCNancyBootstrapper.cs" />
|
<Compile Include="TinyIoCNancyBootstrapper.cs" />
|
||||||
<Compile Include="Update\UpdateModule.cs" />
|
<Compile Include="Update\UpdateModule.cs" />
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.Jobs;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.System.Tasks
|
||||||
|
{
|
||||||
|
public class TaskModule : NzbDroneRestModule<TaskResource>
|
||||||
|
{
|
||||||
|
private readonly ITaskManager _taskManager;
|
||||||
|
|
||||||
|
public TaskModule(ITaskManager taskManager)
|
||||||
|
: base("system/task")
|
||||||
|
{
|
||||||
|
_taskManager = taskManager;
|
||||||
|
GetResourceAll = GetAll;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<TaskResource> GetAll()
|
||||||
|
{
|
||||||
|
return _taskManager.GetAll().Select(ConvertToResource).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TaskResource ConvertToResource(ScheduledTask scheduledTask)
|
||||||
|
{
|
||||||
|
return new TaskResource
|
||||||
|
{
|
||||||
|
Id = scheduledTask.Id,
|
||||||
|
Name = scheduledTask.TypeName.Split('.').Last().Replace("Command", ""),
|
||||||
|
CommandName = scheduledTask.TypeName.Split('.').Last(),
|
||||||
|
Interval = scheduledTask.Interval,
|
||||||
|
LastExecution = scheduledTask.LastExecution,
|
||||||
|
NextExecution = scheduledTask.LastExecution.AddMinutes(scheduledTask.Interval)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using NzbDrone.Api.REST;
|
||||||
|
|
||||||
|
namespace NzbDrone.Api.System.Tasks
|
||||||
|
{
|
||||||
|
public class TaskResource : RestResource
|
||||||
|
{
|
||||||
|
public String Name { get; set; }
|
||||||
|
public String CommandName { get; set; }
|
||||||
|
public Int32 Interval { get; set; }
|
||||||
|
public DateTime LastExecution { get; set; }
|
||||||
|
public DateTime NextExecution { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ namespace NzbDrone.Core.Jobs
|
||||||
public interface ITaskManager
|
public interface ITaskManager
|
||||||
{
|
{
|
||||||
IList<ScheduledTask> GetPending();
|
IList<ScheduledTask> GetPending();
|
||||||
|
List<ScheduledTask> GetAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class TaskManager : ITaskManager, IHandle<ApplicationStartedEvent>, IHandle<CommandExecutedEvent>, IHandleAsync<ConfigSavedEvent>
|
public class TaskManager : ITaskManager, IHandle<ApplicationStartedEvent>, IHandle<CommandExecutedEvent>, IHandleAsync<ConfigSavedEvent>
|
||||||
|
@ -45,6 +46,11 @@ namespace NzbDrone.Core.Jobs
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<ScheduledTask> GetAll()
|
||||||
|
{
|
||||||
|
return _scheduledTaskRepository.All().ToList();
|
||||||
|
}
|
||||||
|
|
||||||
public void Handle(ApplicationStartedEvent message)
|
public void Handle(ApplicationStartedEvent message)
|
||||||
{
|
{
|
||||||
var defaultTasks = new[]
|
var defaultTasks = new[]
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'Cells/NzbDroneCell',
|
||||||
|
'moment',
|
||||||
|
'Shared/FormatHelpers',
|
||||||
|
'Shared/UiSettingsModel'
|
||||||
|
], function (NzbDroneCell, moment, FormatHelpers, UiSettings) {
|
||||||
|
return NzbDroneCell.extend({
|
||||||
|
|
||||||
|
className: 'relative-time-cell',
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
|
||||||
|
var dateStr = this.model.get(this.column.get('name'));
|
||||||
|
|
||||||
|
if (dateStr) {
|
||||||
|
var date = moment(dateStr);
|
||||||
|
var result = '<span title="{0}">{1}</span>';
|
||||||
|
|
||||||
|
if (UiSettings.get('showRelativeDates')) {
|
||||||
|
var tooltip = date.format(UiSettings.longDateTime());
|
||||||
|
var text = date.fromNow();
|
||||||
|
|
||||||
|
this.$el.html(result.format(tooltip, text));
|
||||||
|
}
|
||||||
|
|
||||||
|
else {
|
||||||
|
this.$el.html(date.format(UiSettings.longDateTime()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -50,6 +50,11 @@
|
||||||
.text-overflow();
|
.text-overflow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.relative-time-cell {
|
||||||
|
cursor: default;
|
||||||
|
.text-overflow();
|
||||||
|
}
|
||||||
|
|
||||||
.history-event-type-cell {
|
.history-event-type-cell {
|
||||||
width : 10px;
|
width : 10px;
|
||||||
}
|
}
|
||||||
|
@ -193,3 +198,11 @@ td.delete-episode-file-cell {
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.execute-task-cell {
|
||||||
|
width : 28px;
|
||||||
|
|
||||||
|
i {
|
||||||
|
.clickable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ define(
|
||||||
'System/Logs/LogsLayout',
|
'System/Logs/LogsLayout',
|
||||||
'System/Update/UpdateLayout',
|
'System/Update/UpdateLayout',
|
||||||
'System/Backup/BackupLayout',
|
'System/Backup/BackupLayout',
|
||||||
|
'System/Task/TaskLayout',
|
||||||
'Shared/Messenger'
|
'Shared/Messenger'
|
||||||
], function ($,
|
], function ($,
|
||||||
Backbone,
|
Backbone,
|
||||||
|
@ -16,6 +17,7 @@ define(
|
||||||
LogsLayout,
|
LogsLayout,
|
||||||
UpdateLayout,
|
UpdateLayout,
|
||||||
BackupLayout,
|
BackupLayout,
|
||||||
|
TaskLayout,
|
||||||
Messenger) {
|
Messenger) {
|
||||||
return Marionette.Layout.extend({
|
return Marionette.Layout.extend({
|
||||||
template: 'System/SystemLayoutTemplate',
|
template: 'System/SystemLayoutTemplate',
|
||||||
|
@ -24,14 +26,16 @@ define(
|
||||||
info : '#info',
|
info : '#info',
|
||||||
logs : '#logs',
|
logs : '#logs',
|
||||||
updates : '#updates',
|
updates : '#updates',
|
||||||
backup : '#backup'
|
backup : '#backup',
|
||||||
|
tasks : '#tasks'
|
||||||
},
|
},
|
||||||
|
|
||||||
ui: {
|
ui: {
|
||||||
infoTab : '.x-info-tab',
|
infoTab : '.x-info-tab',
|
||||||
logsTab : '.x-logs-tab',
|
logsTab : '.x-logs-tab',
|
||||||
updatesTab : '.x-updates-tab',
|
updatesTab : '.x-updates-tab',
|
||||||
backupTab : '.x-backup-tab'
|
backupTab : '.x-backup-tab',
|
||||||
|
tasksTab : '.x-tasks-tab'
|
||||||
},
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
|
@ -39,6 +43,7 @@ define(
|
||||||
'click .x-logs-tab' : '_showLogs',
|
'click .x-logs-tab' : '_showLogs',
|
||||||
'click .x-updates-tab' : '_showUpdates',
|
'click .x-updates-tab' : '_showUpdates',
|
||||||
'click .x-backup-tab' : '_showBackup',
|
'click .x-backup-tab' : '_showBackup',
|
||||||
|
'click .x-tasks-tab' : '_showTasks',
|
||||||
'click .x-shutdown' : '_shutdown',
|
'click .x-shutdown' : '_shutdown',
|
||||||
'click .x-restart' : '_restart'
|
'click .x-restart' : '_restart'
|
||||||
},
|
},
|
||||||
|
@ -60,6 +65,9 @@ define(
|
||||||
case 'backup':
|
case 'backup':
|
||||||
this._showBackup();
|
this._showBackup();
|
||||||
break;
|
break;
|
||||||
|
case 'tasks':
|
||||||
|
this._showTasks();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
this._showInfo();
|
this._showInfo();
|
||||||
}
|
}
|
||||||
|
@ -109,6 +117,16 @@ define(
|
||||||
this._navigate('system/backup');
|
this._navigate('system/backup');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_showTasks: function (e) {
|
||||||
|
if (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tasks.show(new TaskLayout());
|
||||||
|
this.ui.tasksTab.tab('show');
|
||||||
|
this._navigate('system/tasks');
|
||||||
|
},
|
||||||
|
|
||||||
_shutdown: function () {
|
_shutdown: function () {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: window.NzbDrone.ApiRoot + '/system/shutdown',
|
url: window.NzbDrone.ApiRoot + '/system/shutdown',
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
<li><a href="#logs" class="x-logs-tab no-router">Logs</a></li>
|
<li><a href="#logs" class="x-logs-tab no-router">Logs</a></li>
|
||||||
<li><a href="#updates" class="x-updates-tab no-router">Updates</a></li>
|
<li><a href="#updates" class="x-updates-tab no-router">Updates</a></li>
|
||||||
<li><a href="#backup" class="x-backup-tab no-router">Backup</a></li>
|
<li><a href="#backup" class="x-backup-tab no-router">Backup</a></li>
|
||||||
|
<li><a href="#tasks" class="x-tasks-tab no-router">Tasks</a></li>
|
||||||
<li class="lifecycle-controls pull-right">
|
<li class="lifecycle-controls pull-right">
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<button class="btn btn-default btn-icon-only x-shutdown" title="Shutdown" data-container="body">
|
<button class="btn btn-default btn-icon-only x-shutdown" title="Shutdown" data-container="body">
|
||||||
|
@ -20,4 +21,5 @@
|
||||||
<div class="tab-pane" id="logs"></div>
|
<div class="tab-pane" id="logs"></div>
|
||||||
<div class="tab-pane" id="updates"></div>
|
<div class="tab-pane" id="updates"></div>
|
||||||
<div class="tab-pane" id="backup"></div>
|
<div class="tab-pane" id="backup"></div>
|
||||||
|
<div class="tab-pane" id="tasks"></div>
|
||||||
</div>
|
</div>
|
|
@ -0,0 +1,41 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'Cells/NzbDroneCell',
|
||||||
|
'Commands/CommandController'
|
||||||
|
], function (NzbDroneCell, CommandController) {
|
||||||
|
return NzbDroneCell.extend({
|
||||||
|
|
||||||
|
className: 'execute-task-cell',
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .x-execute' : '_executeTask'
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
var task = this.model.get('name');
|
||||||
|
|
||||||
|
this.$el.html(
|
||||||
|
'<i class="icon-cogs x-execute" title="Execute {0}"></i>'.format(task)
|
||||||
|
);
|
||||||
|
|
||||||
|
CommandController.bindToCommand({
|
||||||
|
element: this.$el.find('.x-execute'),
|
||||||
|
command: {
|
||||||
|
name : task
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
_executeTask: function () {
|
||||||
|
CommandController.Execute(this.model.get('name'), {
|
||||||
|
name : this.model.get('name')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,19 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'backbone.pageable',
|
||||||
|
'System/Task/TaskModel'
|
||||||
|
], function (PageableCollection, TaskModel) {
|
||||||
|
return PageableCollection.extend({
|
||||||
|
url : window.NzbDrone.ApiRoot + '/system/task',
|
||||||
|
model: TaskModel,
|
||||||
|
|
||||||
|
state: {
|
||||||
|
sortKey : 'name',
|
||||||
|
order : -1,
|
||||||
|
pageSize : 100000
|
||||||
|
},
|
||||||
|
|
||||||
|
mode: 'client'
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,25 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'Cells/NzbDroneCell',
|
||||||
|
'moment'
|
||||||
|
], function (NzbDroneCell, moment) {
|
||||||
|
return NzbDroneCell.extend({
|
||||||
|
|
||||||
|
className: 'task-interval-cell',
|
||||||
|
|
||||||
|
render: function () {
|
||||||
|
|
||||||
|
this.$el.empty();
|
||||||
|
|
||||||
|
var interval = this.model.get('interval');
|
||||||
|
var duration = moment.duration(interval, 'minutes').humanize();
|
||||||
|
|
||||||
|
this.$el.html(
|
||||||
|
duration.replace(/an?(?=\s)/, '1')
|
||||||
|
);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,73 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'marionette',
|
||||||
|
'backgrid',
|
||||||
|
'System/Task/TaskCollection',
|
||||||
|
'Cells/RelativeTimeCell',
|
||||||
|
'System/Task/TaskIntervalCell',
|
||||||
|
'System/Task/ExecuteTaskCell',
|
||||||
|
'Shared/LoadingView'
|
||||||
|
], function (Marionette, Backgrid, BackupCollection, RelativeTimeCell, TaskIntervalCell, ExecuteTaskCell, LoadingView) {
|
||||||
|
return Marionette.Layout.extend({
|
||||||
|
template: 'System/Task/TaskLayoutTemplate',
|
||||||
|
|
||||||
|
regions: {
|
||||||
|
tasks : '#x-tasks'
|
||||||
|
},
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name : 'name',
|
||||||
|
label : 'Name',
|
||||||
|
sortable : true,
|
||||||
|
cell : 'string'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'interval',
|
||||||
|
label : 'Interval',
|
||||||
|
sortable : true,
|
||||||
|
cell : TaskIntervalCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'lastExecution',
|
||||||
|
label : 'Last Execution',
|
||||||
|
sortable : true,
|
||||||
|
cell : RelativeTimeCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'nextExecution',
|
||||||
|
label : 'Next Execution',
|
||||||
|
sortable : true,
|
||||||
|
cell : RelativeTimeCell
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name : 'this',
|
||||||
|
label : '',
|
||||||
|
sortable : false,
|
||||||
|
cell : ExecuteTaskCell
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
initialize: function () {
|
||||||
|
this.taskCollection = new BackupCollection();
|
||||||
|
|
||||||
|
this.listenTo(this.taskCollection, 'sync', this._showTasks);
|
||||||
|
},
|
||||||
|
|
||||||
|
onRender: function () {
|
||||||
|
this.tasks.show(new LoadingView());
|
||||||
|
|
||||||
|
this.taskCollection.fetch();
|
||||||
|
},
|
||||||
|
|
||||||
|
_showTasks: function () {
|
||||||
|
|
||||||
|
this.tasks.show(new Backgrid.Grid({
|
||||||
|
columns : this.columns,
|
||||||
|
collection: this.taskCollection,
|
||||||
|
className : 'table table-hover'
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div id="x-tasks" class="table-responsive"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,9 @@
|
||||||
|
'use strict';
|
||||||
|
define(
|
||||||
|
[
|
||||||
|
'backbone'
|
||||||
|
], function (Backbone) {
|
||||||
|
return Backbone.Model.extend({
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue