mirror of https://github.com/lidarr/Lidarr
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="System\Backup\BackupModule.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="TinyIoCNancyBootstrapper.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
|
||||
{
|
||||
IList<ScheduledTask> GetPending();
|
||||
List<ScheduledTask> GetAll();
|
||||
}
|
||||
|
||||
public class TaskManager : ITaskManager, IHandle<ApplicationStartedEvent>, IHandle<CommandExecutedEvent>, IHandleAsync<ConfigSavedEvent>
|
||||
|
@ -45,6 +46,11 @@ namespace NzbDrone.Core.Jobs
|
|||
.ToList();
|
||||
}
|
||||
|
||||
public List<ScheduledTask> GetAll()
|
||||
{
|
||||
return _scheduledTaskRepository.All().ToList();
|
||||
}
|
||||
|
||||
public void Handle(ApplicationStartedEvent message)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
.relative-time-cell {
|
||||
cursor: default;
|
||||
.text-overflow();
|
||||
}
|
||||
|
||||
.history-event-type-cell {
|
||||
width : 10px;
|
||||
}
|
||||
|
@ -193,3 +198,11 @@ td.delete-episode-file-cell {
|
|||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.execute-task-cell {
|
||||
width : 28px;
|
||||
|
||||
i {
|
||||
.clickable();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ define(
|
|||
'System/Logs/LogsLayout',
|
||||
'System/Update/UpdateLayout',
|
||||
'System/Backup/BackupLayout',
|
||||
'System/Task/TaskLayout',
|
||||
'Shared/Messenger'
|
||||
], function ($,
|
||||
Backbone,
|
||||
|
@ -16,6 +17,7 @@ define(
|
|||
LogsLayout,
|
||||
UpdateLayout,
|
||||
BackupLayout,
|
||||
TaskLayout,
|
||||
Messenger) {
|
||||
return Marionette.Layout.extend({
|
||||
template: 'System/SystemLayoutTemplate',
|
||||
|
@ -24,21 +26,24 @@ define(
|
|||
info : '#info',
|
||||
logs : '#logs',
|
||||
updates : '#updates',
|
||||
backup : '#backup'
|
||||
backup : '#backup',
|
||||
tasks : '#tasks'
|
||||
},
|
||||
|
||||
ui: {
|
||||
infoTab : '.x-info-tab',
|
||||
logsTab : '.x-logs-tab',
|
||||
updatesTab : '.x-updates-tab',
|
||||
backupTab : '.x-backup-tab'
|
||||
backupTab : '.x-backup-tab',
|
||||
tasksTab : '.x-tasks-tab'
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .x-info-tab' : '_showInfo',
|
||||
'click .x-logs-tab' : '_showLogs',
|
||||
'click .x-updates-tab': '_showUpdates',
|
||||
'click .x-backup-tab': '_showBackup',
|
||||
'click .x-updates-tab' : '_showUpdates',
|
||||
'click .x-backup-tab' : '_showBackup',
|
||||
'click .x-tasks-tab' : '_showTasks',
|
||||
'click .x-shutdown' : '_shutdown',
|
||||
'click .x-restart' : '_restart'
|
||||
},
|
||||
|
@ -60,6 +65,9 @@ define(
|
|||
case 'backup':
|
||||
this._showBackup();
|
||||
break;
|
||||
case 'tasks':
|
||||
this._showTasks();
|
||||
break;
|
||||
default:
|
||||
this._showInfo();
|
||||
}
|
||||
|
@ -109,6 +117,16 @@ define(
|
|||
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 () {
|
||||
$.ajax({
|
||||
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="#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="#tasks" class="x-tasks-tab no-router">Tasks</a></li>
|
||||
<li class="lifecycle-controls pull-right">
|
||||
<div class="btn-group">
|
||||
<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="updates"></div>
|
||||
<div class="tab-pane" id="backup"></div>
|
||||
<div class="tab-pane" id="tasks"></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