UI Cleanup - Updated System, Tags and Wanted subtrees.

pull/4/head
Taloth Saldono 9 years ago
parent d6079a701c
commit 32fc68b9df

@ -4,10 +4,12 @@ var BackupModel = require('./BackupModel');
module.exports = PageableCollection.extend({ module.exports = PageableCollection.extend({
url : window.NzbDrone.ApiRoot + '/system/backup', url : window.NzbDrone.ApiRoot + '/system/backup',
model : BackupModel, model : BackupModel,
state : { state : {
sortKey : 'time', sortKey : 'time',
order : 1, order : 1,
pageSize : 100000 pageSize : 100000
}, },
mode : 'client' mode : 'client'
}); });

@ -1,3 +1,5 @@
var Marionette = require('marionette'); var Marionette = require('marionette');
module.exports = Marionette.ItemView.extend({template : 'System/Backup/BackupEmptyViewTemplate'}); module.exports = Marionette.ItemView.extend({
template : 'System/Backup/BackupEmptyViewTemplate'
});

@ -11,54 +11,67 @@ var ToolbarLayout = require('../../Shared/Toolbar/ToolbarLayout');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Backup/BackupLayoutTemplate', template : 'System/Backup/BackupLayoutTemplate',
regions : { regions : {
backups : '#x-backups', backups : '#x-backups',
toolbar : '#x-backup-toolbar' toolbar : '#x-backup-toolbar'
}, },
columns : [{
columns : [
{
name : 'type', name : 'type',
label : '', label : '',
sortable : false, sortable : false,
cell : BackupTypeCell cell : BackupTypeCell
}, { },
{
name : 'this', name : 'this',
label : 'Name', label : 'Name',
sortable : false, sortable : false,
cell : BackupFilenameCell cell : BackupFilenameCell
}, { },
{
name : 'time', name : 'time',
label : 'Time', label : 'Time',
sortable : false, sortable : false,
cell : RelativeDateCell cell : RelativeDateCell
}], }
],
leftSideButtons : { leftSideButtons : {
type : 'default', type : 'default',
storeState : false, storeState : false,
collapse : false, collapse : false,
items : [{ items : [
{
title : 'Backup', title : 'Backup',
icon : 'icon-file-text', icon : 'icon-file-text',
command : 'backup', command : 'backup',
properties : { type : 'manual' }, properties : { type : 'manual' },
successMessage : 'Database and settings were backed up successfully', successMessage : 'Database and settings were backed up successfully',
errorMessage : 'Backup Failed!' errorMessage : 'Backup Failed!'
}] }
]
}, },
initialize : function() { initialize : function() {
this.backupCollection = new BackupCollection(); this.backupCollection = new BackupCollection();
this.listenTo(this.backupCollection, 'sync', this._showBackups); this.listenTo(this.backupCollection, 'sync', this._showBackups);
this.listenTo(vent, vent.Events.CommandComplete, this._commandComplete); this.listenTo(vent, vent.Events.CommandComplete, this._commandComplete);
}, },
onRender : function() { onRender : function() {
this._showToolbar(); this._showToolbar();
this.backups.show(new LoadingView()); this.backups.show(new LoadingView());
this.backupCollection.fetch(); this.backupCollection.fetch();
}, },
_showBackups : function() { _showBackups : function() {
if (this.backupCollection.length === 0) { if (this.backupCollection.length === 0) {
this.backups.show(new EmptyView()); this.backups.show(new EmptyView());
} } else {
else {
this.backups.show(new Backgrid.Grid({ this.backups.show(new Backgrid.Grid({
columns : this.columns, columns : this.columns,
collection : this.backupCollection, collection : this.backupCollection,
@ -66,6 +79,7 @@ module.exports = Marionette.Layout.extend({
})); }));
} }
}, },
_showToolbar : function() { _showToolbar : function() {
this.toolbar.show(new ToolbarLayout({ this.toolbar.show(new ToolbarLayout({
left : [this.leftSideButtons], left : [this.leftSideButtons],

@ -2,20 +2,25 @@ var NzbDroneCell = require('../../Cells/NzbDroneCell');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'backup-type-cell', className : 'backup-type-cell',
render : function() { render : function() {
this.$el.empty(); this.$el.empty();
var icon = 'icon-time'; var icon = 'icon-time';
var title = 'Scheduled'; var title = 'Scheduled';
var type = this.model.get(this.column.get('name')); var type = this.model.get(this.column.get('name'));
if (type === 'manual') { if (type === 'manual') {
icon = 'icon-book'; icon = 'icon-book';
title = 'Manual'; title = 'Manual';
} } else if (type === 'update') {
else if(type === 'update') {
icon = 'icon-retweet'; icon = 'icon-retweet';
title = 'Before update'; title = 'Before update';
} }
this.$el.html('<i class="{0}" title="{1}"></i>'.format(icon, title)); this.$el.html('<i class="{0}" title="{1}"></i>'.format(icon, title));
return this; return this;
} }
}); });

@ -3,6 +3,7 @@ var StatusModel = require('../../StatusModel');
module.exports = Marionette.ItemView.extend({ module.exports = Marionette.ItemView.extend({
template : 'System/Info/About/AboutViewTemplate', template : 'System/Info/About/AboutViewTemplate',
initialize : function() { initialize : function() {
this.model = StatusModel; this.model = StatusModel;
} }

@ -1,4 +1,4 @@
var vent = require('vent'); var vent = require('vent');
var Marionette = require('marionette'); var Marionette = require('marionette');
var Backgrid = require('backgrid'); var Backgrid = require('backgrid');
var DiskSpaceCollection = require('./DiskSpaceCollection'); var DiskSpaceCollection = require('./DiskSpaceCollection');
@ -8,33 +8,45 @@ var FileSizeCell = require('../../../Cells/FileSizeCell');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Info/DiskSpace/DiskSpaceLayoutTemplate', template : 'System/Info/DiskSpace/DiskSpaceLayoutTemplate',
regions : {grid : '#x-grid'},
columns : [{ regions : {
grid : '#x-grid'
},
columns : [
{
name : 'path', name : 'path',
label : 'Location', label : 'Location',
cell : DiskSpacePathCell, cell : DiskSpacePathCell,
sortable : false sortable : false
}, { },
{
name : 'freeSpace', name : 'freeSpace',
label : 'Free Space', label : 'Free Space',
cell : FileSizeCell, cell : FileSizeCell,
sortable : false sortable : false
}, { },
{
name : 'totalSpace', name : 'totalSpace',
label : 'Total Space', label : 'Total Space',
cell : FileSizeCell, cell : FileSizeCell,
sortable : false sortable : false
}], }
],
initialize : function() { initialize : function() {
this.collection = new DiskSpaceCollection(); this.collection = new DiskSpaceCollection();
this.listenTo(this.collection, 'sync', this._showTable); this.listenTo(this.collection, 'sync', this._showTable);
}, },
onRender : function() { onRender : function() {
this.grid.show(new LoadingView()); this.grid.show(new LoadingView());
}, },
onShow : function() { onShow : function() {
this.collection.fetch(); this.collection.fetch();
}, },
_showTable : function() { _showTable : function() {
this.grid.show(new Backgrid.Grid({ this.grid.show(new Backgrid.Grid({
row : Backgrid.Row, row : Backgrid.Row,

@ -2,15 +2,21 @@ var Backgrid = require('backgrid');
module.exports = Backgrid.Cell.extend({ module.exports = Backgrid.Cell.extend({
className : 'disk-space-path-cell', className : 'disk-space-path-cell',
render : function() { render : function() {
this.$el.empty(); this.$el.empty();
var path = this.model.get('path'); var path = this.model.get('path');
var label = this.model.get('label'); var label = this.model.get('label');
var contents = path; var contents = path;
if (label) { if (label) {
contents += ' ({0})'.format(label); contents += ' ({0})'.format(label);
} }
this.$el.html(contents); this.$el.html(contents);
return this; return this;
} }
}); });

@ -2,9 +2,11 @@ var NzbDroneCell = require('../../../Cells/NzbDroneCell');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'log-level-cell', className : 'log-level-cell',
render : function() { render : function() {
var level = this._getValue(); var level = this._getValue();
this.$el.html('<i class="icon-nd-health-{0}" title="{1}"/>'.format(this._getValue().toLowerCase(), level)); this.$el.html('<i class="icon-nd-health-{0}" title="{1}"/>'.format(this._getValue().toLowerCase(), level));
return this; return this;
} }
}); });

@ -7,35 +7,45 @@ var HealthOkView = require('./HealthOkView');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Info/Health/HealthLayoutTemplate', template : 'System/Info/Health/HealthLayoutTemplate',
regions : {grid : '#x-health-grid'},
columns : [{ regions : {
grid : '#x-health-grid'
},
columns : [
{
name : 'type', name : 'type',
label : '', label : '',
cell : HealthCell, cell : HealthCell,
sortable : false sortable : false
}, { },
{
name : 'message', name : 'message',
label : 'Message', label : 'Message',
cell : 'string', cell : 'string',
sortable : false sortable : false
}, { },
{
name : 'wikiUrl', name : 'wikiUrl',
label : '', label : '',
cell : HealthWikiCell, cell : HealthWikiCell,
sortable : false sortable : false
}], }
],
initialize : function() { initialize : function() {
this.listenTo(HealthCollection, 'sync', this.render); this.listenTo(HealthCollection, 'sync', this.render);
HealthCollection.fetch(); HealthCollection.fetch();
}, },
onRender : function() { onRender : function() {
if (HealthCollection.length === 0) { if (HealthCollection.length === 0) {
this.grid.show(new HealthOkView()); this.grid.show(new HealthOkView());
} } else {
else {
this._showTable(); this._showTable();
} }
}, },
_showTable : function() { _showTable : function() {
this.grid.show(new Backgrid.Grid({ this.grid.show(new Backgrid.Grid({
row : Backgrid.Row, row : Backgrid.Row,

@ -1,3 +1,5 @@
var Marionette = require('marionette'); var Marionette = require('marionette');
module.exports = Marionette.ItemView.extend({template : 'System/Info/Health/HealthOkViewTemplate'}); module.exports = Marionette.ItemView.extend({
template : 'System/Info/Health/HealthOkViewTemplate'
});

@ -3,8 +3,11 @@ var Backgrid = require('backgrid');
module.exports = Backgrid.UriCell.extend({ module.exports = Backgrid.UriCell.extend({
className : 'wiki-link-cell', className : 'wiki-link-cell',
title : 'Read the Wiki for more information', title : 'Read the Wiki for more information',
text : 'Wiki', text : 'Wiki',
render : function() { render : function() {
this.$el.empty(); this.$el.empty();
var rawValue = this.model.get(this.column.get('name')); var rawValue = this.model.get(this.column.get('name'));

@ -1,3 +1,5 @@
var Marionette = require('marionette'); var Marionette = require('marionette');
module.exports = Marionette.ItemView.extend({template : 'System/Info/MoreInfo/MoreInfoViewTemplate'}); module.exports = Marionette.ItemView.extend({
template : 'System/Info/MoreInfo/MoreInfoViewTemplate'
});

@ -7,12 +7,14 @@ var MoreInfoView = require('./MoreInfo/MoreInfoView');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Info/SystemInfoLayoutTemplate', template : 'System/Info/SystemInfoLayoutTemplate',
regions : { regions : {
about : '#about', about : '#about',
diskSpace : '#diskspace', diskSpace : '#diskspace',
health : '#health', health : '#health',
moreInfo : '#more-info' moreInfo : '#more-info'
}, },
onRender : function() { onRender : function() {
this.health.show(new HealthLayout()); this.health.show(new HealthLayout());
this.diskSpace.show(new DiskSpaceLayout()); this.diskSpace.show(new DiskSpaceLayout());

@ -4,6 +4,7 @@ module.exports = Backbone.Model.extend({
url : function() { url : function() {
return this.get('contentsUrl'); return this.get('contentsUrl');
}, },
parse : function(contents) { parse : function(contents) {
var response = {}; var response = {};
response.contents = contents; response.contents = contents;

@ -1,3 +1,5 @@
var Marionette = require('marionette'); var Marionette = require('marionette');
module.exports = Marionette.ItemView.extend({template : 'System/Logs/Files/ContentsViewTemplate'}); module.exports = Marionette.ItemView.extend({
template : 'System/Logs/Files/ContentsViewTemplate'
});

@ -2,9 +2,11 @@ var NzbDroneCell = require('../../../Cells/NzbDroneCell');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'download-log-cell', className : 'download-log-cell',
render : function() { render : function() {
this.$el.empty(); this.$el.empty();
this.$el.html('<a href="{0}" class="no-router" target="_blank">Download</a>'.format(this.cellValue)); this.$el.html('<a href="{0}" class="no-router" target="_blank">Download</a>'.format(this.cellValue));
return this; return this;
} }
}); });

@ -2,9 +2,11 @@ var NzbDroneCell = require('../../../Cells/NzbDroneCell');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'log-filename-cell', className : 'log-filename-cell',
render : function() { render : function() {
var filename = this._getValue(); var filename = this._getValue();
this.$el.html(filename); this.$el.html(filename);
return this; return this;
} }
}); });

@ -4,6 +4,7 @@ var LogFileModel = require('./LogFileModel');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
url : window.NzbDrone.ApiRoot + '/log/file', url : window.NzbDrone.ApiRoot + '/log/file',
model : LogFileModel, model : LogFileModel,
state : { state : {
sortKey : 'lastWriteTime', sortKey : 'lastWriteTime',
order : 1 order : 1

@ -13,61 +13,77 @@ require('../../../jQuery/jquery.spin');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Logs/Files/LogFileLayoutTemplate', template : 'System/Logs/Files/LogFileLayoutTemplate',
regions : { regions : {
toolbar : '#x-toolbar', toolbar : '#x-toolbar',
grid : '#x-grid', grid : '#x-grid',
contents : '#x-contents' contents : '#x-contents'
}, },
columns : [{
columns : [
{
name : 'filename', name : 'filename',
label : 'Filename', label : 'Filename',
cell : FilenameCell, cell : FilenameCell,
sortable : false sortable : false
}, { },
{
name : 'lastWriteTime', name : 'lastWriteTime',
label : 'Last Write Time', label : 'Last Write Time',
cell : RelativeDateCell, cell : RelativeDateCell,
sortable : false sortable : false
}, { },
{
name : 'downloadUrl', name : 'downloadUrl',
label : '', label : '',
cell : DownloadLogCell, cell : DownloadLogCell,
sortable : false sortable : false
}], }
],
initialize : function(options) { initialize : function(options) {
this.collection = options.collection; this.collection = options.collection;
this.deleteFilesCommand = options.deleteFilesCommand; this.deleteFilesCommand = options.deleteFilesCommand;
this.listenTo(vent, vent.Commands.ShowLogFile, this._fetchLogFileContents); this.listenTo(vent, vent.Commands.ShowLogFile, this._fetchLogFileContents);
this.listenTo(vent, vent.Events.CommandComplete, this._commandComplete); this.listenTo(vent, vent.Events.CommandComplete, this._commandComplete);
this.listenTo(this.collection, 'sync', this._collectionSynced); this.listenTo(this.collection, 'sync', this._collectionSynced);
this.collection.fetch(); this.collection.fetch();
}, },
onShow : function() { onShow : function() {
this._showToolbar(); this._showToolbar();
this._showTable(); this._showTable();
}, },
_showToolbar : function() { _showToolbar : function() {
var leftSideButtons = { var leftSideButtons = {
type : 'default', type : 'default',
storeState : false, storeState : false,
items : [{ items : [
{
title : 'Refresh', title : 'Refresh',
icon : 'icon-refresh', icon : 'icon-refresh',
ownerContext : this, ownerContext : this,
callback : this._refreshTable callback : this._refreshTable
}, { },
{
title : 'Delete Log Files', title : 'Delete Log Files',
icon : 'icon-trash', icon : 'icon-trash',
command : this.deleteFilesCommand, command : this.deleteFilesCommand,
successMessage : 'Log files have been deleted', successMessage : 'Log files have been deleted',
errorMessage : 'Failed to delete log files' errorMessage : 'Failed to delete log files'
}] }
]
}; };
this.toolbar.show(new ToolbarLayout({ this.toolbar.show(new ToolbarLayout({
left : [leftSideButtons], left : [leftSideButtons],
context : this context : this
})); }));
}, },
_showTable : function() { _showTable : function() {
this.grid.show(new Backgrid.Grid({ this.grid.show(new Backgrid.Grid({
row : LogFileRow, row : LogFileRow,
@ -76,30 +92,41 @@ module.exports = Marionette.Layout.extend({
className : 'table table-hover' className : 'table table-hover'
})); }));
}, },
_collectionSynced : function() { _collectionSynced : function() {
if (!this.collection.any()) { if (!this.collection.any()) {
return; return;
} }
var model = this.collection.first(); var model = this.collection.first();
this._fetchLogFileContents({ model : model }); this._fetchLogFileContents({ model : model });
}, },
_fetchLogFileContents : function(options) { _fetchLogFileContents : function(options) {
this.contents.show(new LoadingView()); this.contents.show(new LoadingView());
var model = options.model; var model = options.model;
var contentsModel = new ContentsModel(model.toJSON()); var contentsModel = new ContentsModel(model.toJSON());
this.listenToOnce(contentsModel, 'sync', this._showDetails); this.listenToOnce(contentsModel, 'sync', this._showDetails);
contentsModel.fetch({ dataType : 'text' }); contentsModel.fetch({ dataType : 'text' });
}, },
_showDetails : function(model) { _showDetails : function(model) {
this.contents.show(new ContentsView({ model : model })); this.contents.show(new ContentsView({ model : model }));
}, },
_refreshTable : function(buttonContext) { _refreshTable : function(buttonContext) {
this.contents.close(); this.contents.close();
var promise = this.collection.fetch(); var promise = this.collection.fetch();
//Would be nice to spin the icon on the refresh button
if (buttonContext) { if (buttonContext) {
buttonContext.ui.icon.spinForPromise(promise); buttonContext.ui.icon.spinForPromise(promise);
} }
}, },
_commandComplete : function(options) { _commandComplete : function(options) {
if (options.command.get('name') === this.deleteFilesCommand.toLowerCase()) { if (options.command.get('name') === this.deleteFilesCommand.toLowerCase()) {
this._refreshTable(); this._refreshTable();

@ -3,7 +3,11 @@ var Backgrid = require('backgrid');
module.exports = Backgrid.Row.extend({ module.exports = Backgrid.Row.extend({
className : 'log-file-row', className : 'log-file-row',
events : {"click" : '_showDetails'},
events : {
'click' : '_showDetails'
},
_showDetails : function() { _showDetails : function() {
vent.trigger(vent.Commands.ShowLogFile, { model : this.model }); vent.trigger(vent.Commands.ShowLogFile, { model : this.model });
} }

@ -3,16 +3,17 @@ var LogsModel = require('./LogsModel');
var AsFilteredCollection = require('../../Mixins/AsFilteredCollection'); var AsFilteredCollection = require('../../Mixins/AsFilteredCollection');
var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollection'); var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollection');
module.exports = (function(){
var collection = PagableCollection.extend({ var collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/log', url : window.NzbDrone.ApiRoot + '/log',
model : LogsModel, model : LogsModel,
tableName : 'logs', tableName : 'logs',
state : { state : {
pageSize : 50, pageSize : 50,
sortKey : 'time', sortKey : 'time',
order : 1 order : 1
}, },
queryParams : { queryParams : {
totalPages : null, totalPages : null,
totalRecords : null, totalRecords : null,
@ -20,26 +21,44 @@ module.exports = (function(){
sortKey : 'sortKey', sortKey : 'sortKey',
order : 'sortDir', order : 'sortDir',
directions : { directions : {
"-1" : 'asc', '-1' : 'asc',
"1" : 'desc' '1' : 'desc'
} }
}, },
// Filter Modes
filterModes : { filterModes : {
"all" : [null, null], "all" : [
"info" : ['level', 'Info'], null,
"warn" : ['level', 'Warn'], null
"error" : ['level', 'Error'] ],
"info" : [
'level',
'Info'
],
"warn" : [
'level',
'Warn'
],
"error" : [
'level',
'Error'
]
}, },
parseState : function(resp, queryParams, state) { parseState : function(resp, queryParams, state) {
return { totalRecords : resp.totalRecords }; return { totalRecords : resp.totalRecords };
}, },
parseRecords : function(resp) { parseRecords : function(resp) {
if (resp) { if (resp) {
return resp.records; return resp.records;
} }
return resp; return resp;
} }
}); });
collection = AsFilteredCollection.apply(collection); collection = AsFilteredCollection.apply(collection);
return AsPersistedStateCollection.apply(collection);
}).call(this); module.exports = AsPersistedStateCollection.apply(collection);

@ -6,45 +6,55 @@ var UpdateLogFileCollection = require('./Updates/LogFileCollection');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Logs/LogsLayoutTemplate', template : 'System/Logs/LogsLayoutTemplate',
ui : { ui : {
tableTab : '.x-table-tab', tableTab : '.x-table-tab',
filesTab : '.x-files-tab', filesTab : '.x-files-tab',
updateFilesTab : '.x-update-files-tab' updateFilesTab : '.x-update-files-tab'
}, },
regions : { regions : {
table : '#table', table : '#table',
files : '#files', files : '#files',
updateFiles : '#update-files' updateFiles : '#update-files'
}, },
events : { events : {
"click .x-table-tab" : '_showTable', 'click .x-table-tab' : '_showTable',
"click .x-files-tab" : '_showFiles', 'click .x-files-tab' : '_showFiles',
"click .x-update-files-tab" : '_showUpdateFiles' 'click .x-update-files-tab' : '_showUpdateFiles'
}, },
onShow : function() { onShow : function() {
this._showTable(); this._showTable();
}, },
_showTable : function(e) { _showTable : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.ui.tableTab.tab('show'); this.ui.tableTab.tab('show');
this.table.show(new LogsTableLayout()); this.table.show(new LogsTableLayout());
}, },
_showFiles : function(e) { _showFiles : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.ui.filesTab.tab('show'); this.ui.filesTab.tab('show');
this.files.show(new LogsFileLayout({ this.files.show(new LogsFileLayout({
collection : new LogFileCollection(), collection : new LogFileCollection(),
deleteFilesCommand : 'deleteLogFiles' deleteFilesCommand : 'deleteLogFiles'
})); }));
}, },
_showUpdateFiles : function(e) { _showUpdateFiles : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.ui.updateFilesTab.tab('show'); this.ui.updateFilesTab.tab('show');
this.updateFiles.show(new LogsFileLayout({ this.updateFiles.show(new LogsFileLayout({
collection : new UpdateLogFileCollection(), collection : new UpdateLogFileCollection(),

@ -1,4 +1,6 @@
var vent = require('vent'); var vent = require('vent');
var Marionette = require('marionette'); var Marionette = require('marionette');
module.exports = Marionette.ItemView.extend({template : 'System/Logs/Table/Details/LogDetailsViewTemplate'}); module.exports = Marionette.ItemView.extend({
template : 'System/Logs/Table/Details/LogDetailsViewTemplate'
});

@ -2,9 +2,11 @@ var NzbDroneCell = require('../../../Cells/NzbDroneCell');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'log-level-cell', className : 'log-level-cell',
render : function() { render : function() {
var level = this._getValue(); var level = this._getValue();
this.$el.html('<i class="icon-{0}" title="{1}"/>'.format(this._getValue().toLowerCase(), level)); this.$el.html('<i class="icon-{0}" title="{1}"/>'.format(this._getValue().toLowerCase(), level));
return this; return this;
} }
}); });

@ -3,7 +3,11 @@ var Backgrid = require('backgrid');
module.exports = Backgrid.Row.extend({ module.exports = Backgrid.Row.extend({
className : 'log-row', className : 'log-row',
events : {"click" : '_showDetails'},
events : {
'click' : '_showDetails'
},
_showDetails : function() { _showDetails : function() {
vent.trigger(vent.Commands.ShowLogDetails, { model : this.model }); vent.trigger(vent.Commands.ShowLogDetails, { model : this.model });
} }

@ -4,9 +4,11 @@ var UiSettings = require('../../../Shared/UiSettingsModel');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'log-time-cell', className : 'log-time-cell',
render : function() { render : function() {
var date = moment(this._getValue()); var date = moment(this._getValue());
this.$el.html('<span title="{1}">{0}</span>'.format(date.format(UiSettings.time(true, false)), date.format(UiSettings.longDateTime(true)))); this.$el.html('<span title="{1}">{0}</span>'.format(date.format(UiSettings.time(true, false)), date.format(UiSettings.longDateTime(true))));
return this; return this;
} }
}); });

@ -12,43 +12,62 @@ require('../../../jQuery/jquery.spin');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Logs/Table/LogsTableLayoutTemplate', template : 'System/Logs/Table/LogsTableLayoutTemplate',
regions : { regions : {
grid : '#x-grid', grid : '#x-grid',
toolbar : '#x-toolbar', toolbar : '#x-toolbar',
pager : '#x-pager' pager : '#x-pager'
}, },
attributes : {id : 'logs-screen'},
columns : [{ attributes : {
id : 'logs-screen'
},
columns : [
{
name : 'level', name : 'level',
label : '', label : '',
sortable : true, sortable : true,
cell : LogLevelCell cell : LogLevelCell
}, { },
{
name : 'logger', name : 'logger',
label : 'Component', label : 'Component',
sortable : true, sortable : true,
cell : Backgrid.StringCell.extend({className : 'log-logger-cell'}) cell : Backgrid.StringCell.extend({
}, { className : 'log-logger-cell'
})
},
{
name : 'message', name : 'message',
label : 'Message', label : 'Message',
sortable : false, sortable : false,
cell : Backgrid.StringCell.extend({className : 'log-message-cell'}) cell : Backgrid.StringCell.extend({
}, { className : 'log-message-cell'
})
},
{
name : 'time', name : 'time',
label : 'Time', label : 'Time',
cell : LogTimeCell cell : LogTimeCell
}], }
],
initialize : function() { initialize : function() {
this.collection = new LogCollection(); this.collection = new LogCollection();
this.listenTo(this.collection, 'sync', this._showTable); this.listenTo(this.collection, 'sync', this._showTable);
this.listenTo(vent, vent.Events.CommandComplete, this._commandComplete); this.listenTo(vent, vent.Events.CommandComplete, this._commandComplete);
}, },
onRender : function() { onRender : function() {
this.grid.show(new LoadingView()); this.grid.show(new LoadingView());
}, },
onShow : function() { onShow : function() {
this._showToolbar(); this._showToolbar();
}, },
_showTable : function() { _showTable : function() {
this.grid.show(new Backgrid.Grid({ this.grid.show(new Backgrid.Grid({
row : LogRow, row : LogRow,
@ -56,79 +75,98 @@ module.exports = Marionette.Layout.extend({
collection : this.collection, collection : this.collection,
className : 'table table-hover' className : 'table table-hover'
})); }));
this.pager.show(new GridPager({ this.pager.show(new GridPager({
columns : this.columns, columns : this.columns,
collection : this.collection collection : this.collection
})); }));
}, },
_showToolbar : function() { _showToolbar : function() {
var filterButtons = { var filterButtons = {
type : 'radio', type : 'radio',
storeState : true, storeState : true,
menuKey : 'logs.filterMode', menuKey : 'logs.filterMode',
defaultAction : 'all', defaultAction : 'all',
items : [{ items : [
{
key : 'all', key : 'all',
title : '', title : '',
tooltip : 'All', tooltip : 'All',
icon : 'icon-circle-blank', icon : 'icon-circle-blank',
callback : this._setFilter callback : this._setFilter
}, { },
{
key : 'info', key : 'info',
title : '', title : '',
tooltip : 'Info', tooltip : 'Info',
icon : 'icon-info', icon : 'icon-info',
callback : this._setFilter callback : this._setFilter
}, { },
{
key : 'warn', key : 'warn',
title : '', title : '',
tooltip : 'Warn', tooltip : 'Warn',
icon : 'icon-warn', icon : 'icon-warn',
callback : this._setFilter callback : this._setFilter
}, { },
{
key : 'error', key : 'error',
title : '', title : '',
tooltip : 'Error', tooltip : 'Error',
icon : 'icon-error', icon : 'icon-error',
callback : this._setFilter callback : this._setFilter
}] }
]
}; };
var leftSideButtons = { var leftSideButtons = {
type : 'default', type : 'default',
storeState : false, storeState : false,
items : [{ items : [
{
title : 'Refresh', title : 'Refresh',
icon : 'icon-refresh', icon : 'icon-refresh',
ownerContext : this, ownerContext : this,
callback : this._refreshTable callback : this._refreshTable
}, { },
{
title : 'Clear Logs', title : 'Clear Logs',
icon : 'icon-trash', icon : 'icon-trash',
command : 'clearLog' command : 'clearLog'
}] }
]
}; };
this.toolbar.show(new ToolbarLayout({ this.toolbar.show(new ToolbarLayout({
left : [leftSideButtons], left : [leftSideButtons],
right : [filterButtons], right : [filterButtons],
context : this context : this
})); }));
}, },
_refreshTable : function(buttonContext) { _refreshTable : function(buttonContext) {
this.collection.state.currentPage = 1; this.collection.state.currentPage = 1;
var promise = this.collection.fetch({ reset : true }); var promise = this.collection.fetch({ reset : true });
if (buttonContext) { if (buttonContext) {
buttonContext.ui.icon.spinForPromise(promise); buttonContext.ui.icon.spinForPromise(promise);
} }
}, },
_setFilter : function(buttonContext) { _setFilter : function(buttonContext) {
var mode = buttonContext.model.get('key'); var mode = buttonContext.model.get('key');
this.collection.setFilterMode(mode, { reset : false }); this.collection.setFilterMode(mode, { reset : false });
this.collection.state.currentPage = 1; this.collection.state.currentPage = 1;
var promise = this.collection.fetch({ reset : true }); var promise = this.collection.fetch({ reset : true });
if (buttonContext) { if (buttonContext) {
buttonContext.ui.icon.spinForPromise(promise); buttonContext.ui.icon.spinForPromise(promise);
} }
}, },
_commandComplete : function(options) { _commandComplete : function(options) {
if (options.command.get('name') === 'clearlog') { if (options.command.get('name') === 'clearlog') {
this._refreshTable(); this._refreshTable();

@ -4,6 +4,7 @@ var LogFileModel = require('./LogFileModel');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
url : window.NzbDrone.ApiRoot + '/log/file/update', url : window.NzbDrone.ApiRoot + '/log/file/update',
model : LogFileModel, model : LogFileModel,
state : { state : {
sortKey : 'lastWriteTime', sortKey : 'lastWriteTime',
order : 1 order : 1

@ -1,8 +1,9 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
var ApiData = require('../Shared/ApiData'); var ApiData = require('../Shared/ApiData');
module.exports = (function(){ var StatusModel = Backbone.Model.extend({
var StatusModel = Backbone.Model.extend({url : window.NzbDrone.ApiRoot + '/system/status'}); url : window.NzbDrone.ApiRoot + '/system/status'
});
var instance = new StatusModel(ApiData.get('system/status')); var instance = new StatusModel(ApiData.get('system/status'));
return instance;
}).call(this); module.exports = instance;

@ -1,4 +1,4 @@
var $ = require('jquery'); var $ = require('jquery');
var Backbone = require('backbone'); var Backbone = require('backbone');
var Marionette = require('marionette'); var Marionette = require('marionette');
var SystemInfoLayout = require('./Info/SystemInfoLayout'); var SystemInfoLayout = require('./Info/SystemInfoLayout');
@ -11,6 +11,7 @@ var StatusModel = require('./StatusModel');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/SystemLayoutTemplate', template : 'System/SystemLayoutTemplate',
regions : { regions : {
status : '#status', status : '#status',
logs : '#logs', logs : '#logs',
@ -18,6 +19,7 @@ module.exports = Marionette.Layout.extend({
backup : '#backup', backup : '#backup',
tasks : '#tasks' tasks : '#tasks'
}, },
ui : { ui : {
statusTab : '.x-status-tab', statusTab : '.x-status-tab',
logsTab : '.x-logs-tab', logsTab : '.x-logs-tab',
@ -25,6 +27,7 @@ module.exports = Marionette.Layout.extend({
backupTab : '.x-backup-tab', backupTab : '.x-backup-tab',
tasksTab : '.x-tasks-tab' tasksTab : '.x-tasks-tab'
}, },
events : { events : {
'click .x-status-tab' : '_showStatus', 'click .x-status-tab' : '_showStatus',
'click .x-logs-tab' : '_showLogs', 'click .x-logs-tab' : '_showLogs',
@ -34,6 +37,7 @@ module.exports = Marionette.Layout.extend({
'click .x-shutdown' : '_shutdown', 'click .x-shutdown' : '_shutdown',
'click .x-restart' : '_restart' 'click .x-restart' : '_restart'
}, },
initialize : function(options) { initialize : function(options) {
if (options.action) { if (options.action) {
this.action = options.action.toLowerCase(); this.action = options.action.toLowerCase();
@ -43,6 +47,7 @@ module.exports = Marionette.Layout.extend({
authentication : StatusModel.get('authentication') authentication : StatusModel.get('authentication')
}; };
}, },
onShow : function() { onShow : function() {
switch (this.action) { switch (this.action) {
case 'logs': case 'logs':
@ -61,12 +66,14 @@ module.exports = Marionette.Layout.extend({
this._showStatus(); this._showStatus();
} }
}, },
_navigate : function(route) { _navigate : function(route) {
Backbone.history.navigate(route, { Backbone.history.navigate(route, {
trigger : true, trigger : true,
replace : true replace : true
}); });
}, },
_showStatus : function(e) { _showStatus : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
@ -76,53 +83,65 @@ module.exports = Marionette.Layout.extend({
this.ui.statusTab.tab('show'); this.ui.statusTab.tab('show');
this._navigate('system/status'); this._navigate('system/status');
}, },
_showLogs : function(e) { _showLogs : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.logs.show(new LogsLayout()); this.logs.show(new LogsLayout());
this.ui.logsTab.tab('show'); this.ui.logsTab.tab('show');
this._navigate('system/logs'); this._navigate('system/logs');
}, },
_showUpdates : function(e) { _showUpdates : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.updates.show(new UpdateLayout()); this.updates.show(new UpdateLayout());
this.ui.updatesTab.tab('show'); this.ui.updatesTab.tab('show');
this._navigate('system/updates'); this._navigate('system/updates');
}, },
_showBackup : function(e) { _showBackup : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.backup.show(new BackupLayout()); this.backup.show(new BackupLayout());
this.ui.backupTab.tab('show'); this.ui.backupTab.tab('show');
this._navigate('system/backup'); this._navigate('system/backup');
}, },
_showTasks : function(e) { _showTasks : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.tasks.show(new TaskLayout()); this.tasks.show(new TaskLayout());
this.ui.tasksTab.tab('show'); this.ui.tasksTab.tab('show');
this._navigate('system/tasks'); this._navigate('system/tasks');
}, },
_shutdown : function() { _shutdown : function() {
$.ajax({ $.ajax({
url : window.NzbDrone.ApiRoot + '/system/shutdown', url : window.NzbDrone.ApiRoot + '/system/shutdown',
type : 'POST' type : 'POST'
}); });
Messenger.show({ Messenger.show({
message : 'Sonarr will shutdown shortly', message : 'Sonarr will shutdown shortly',
type : 'info' type : 'info'
}); });
}, },
_restart : function() { _restart : function() {
$.ajax({ $.ajax({
url : window.NzbDrone.ApiRoot + '/system/restart', url : window.NzbDrone.ApiRoot + '/system/restart',
type : 'POST' type : 'POST'
}); });
Messenger.show({ Messenger.show({
message : 'Sonarr will restart shortly', message : 'Sonarr will restart shortly',
type : 'info' type : 'info'

@ -1,4 +1,4 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li><a href="#status" class="x-status-tab no-router">Status</a></li> <li><a href="#status" class="x-status-tab no-router">Status</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="#tasks" class="x-tasks-tab no-router">Tasks</a></li> <li><a href="#tasks" class="x-tasks-tab no-router">Tasks</a></li>

@ -3,18 +3,27 @@ var CommandController = require('../../Commands/CommandController');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'execute-task-cell', className : 'execute-task-cell',
events : {"click .x-execute" : '_executeTask'},
events : {
'click .x-execute' : '_executeTask'
},
render : function() { render : function() {
this.$el.empty(); this.$el.empty();
var name = this.model.get('name'); var name = this.model.get('name');
var task = this.model.get('taskName'); var task = this.model.get('taskName');
this.$el.html('<i class="icon-refresh icon-can-spin x-execute" title="Execute {0}"></i>'.format(name)); this.$el.html('<i class="icon-refresh icon-can-spin x-execute" title="Execute {0}"></i>'.format(name));
CommandController.bindToCommand({ CommandController.bindToCommand({
element : this.$el.find('.x-execute'), element : this.$el.find('.x-execute'),
command : { name : task } command : { name : task }
}); });
return this; return this;
}, },
_executeTask : function() { _executeTask : function() {
CommandController.Execute(this.model.get('taskName'), { name : this.model.get('taskName') }); CommandController.Execute(this.model.get('taskName'), { name : this.model.get('taskName') });
} }

@ -4,28 +4,31 @@ var UiSettings = require('../../Shared/UiSettingsModel');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'next-execution-cell', className : 'next-execution-cell',
render : function() { render : function() {
this.$el.empty(); this.$el.empty();
var interval = this.model.get('interval'); var interval = this.model.get('interval');
var nextExecution = moment(this.model.get('nextExecution')); var nextExecution = moment(this.model.get('nextExecution'));
if (interval === 0) { if (interval === 0) {
this.$el.html('-'); this.$el.html('-');
} } else if (moment().isAfter(nextExecution)) {
else if(moment().isAfter(nextExecution)) {
this.$el.html('now'); this.$el.html('now');
} } else {
else {
var result = '<span title="{0}">{1}</span>'; var result = '<span title="{0}">{1}</span>';
var tooltip = nextExecution.format(UiSettings.longDateTime()); var tooltip = nextExecution.format(UiSettings.longDateTime());
var text; var text;
if (UiSettings.get('showRelativeDates')) { if (UiSettings.get('showRelativeDates')) {
text = nextExecution.fromNow(); text = nextExecution.fromNow();
} } else {
else {
text = nextExecution.format(UiSettings.shortDateTime()); text = nextExecution.format(UiSettings.shortDateTime());
} }
this.$el.html(result.format(tooltip, text)); this.$el.html(result.format(tooltip, text));
} }
return this; return this;
} }
}); });

@ -4,10 +4,12 @@ var TaskModel = require('./TaskModel');
module.exports = PageableCollection.extend({ module.exports = PageableCollection.extend({
url : window.NzbDrone.ApiRoot + '/system/task', url : window.NzbDrone.ApiRoot + '/system/task',
model : TaskModel, model : TaskModel,
state : { state : {
sortKey : 'name', sortKey : 'name',
order : -1, order : -1,
pageSize : 100000 pageSize : 100000
}, },
mode : 'client' mode : 'client'
}); });

@ -3,16 +3,19 @@ var moment = require('moment');
module.exports = NzbDroneCell.extend({ module.exports = NzbDroneCell.extend({
className : 'task-interval-cell', className : 'task-interval-cell',
render : function() { render : function() {
this.$el.empty(); this.$el.empty();
var interval = this.model.get('interval'); var interval = this.model.get('interval');
var duration = moment.duration(interval, 'minutes').humanize().replace(/an?(?=\s)/, '1'); var duration = moment.duration(interval, 'minutes').humanize().replace(/an?(?=\s)/, '1');
if (interval === 0) { if (interval === 0) {
this.$el.html('disabled'); this.$el.html('disabled');
} } else {
else {
this.$el.html(duration); this.$el.html(duration);
} }
return this; return this;
} }
}); });

@ -10,42 +10,57 @@ require('../../Mixins/backbone.signalr.mixin');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Task/TaskLayoutTemplate', template : 'System/Task/TaskLayoutTemplate',
regions : {tasks : '#x-tasks'},
columns : [{ regions : {
tasks : '#x-tasks'
},
columns : [
{
name : 'name', name : 'name',
label : 'Name', label : 'Name',
sortable : true, sortable : true,
cell : 'string' cell : 'string'
}, { },
{
name : 'interval', name : 'interval',
label : 'Interval', label : 'Interval',
sortable : true, sortable : true,
cell : TaskIntervalCell cell : TaskIntervalCell
}, { },
{
name : 'lastExecution', name : 'lastExecution',
label : 'Last Execution', label : 'Last Execution',
sortable : true, sortable : true,
cell : RelativeTimeCell cell : RelativeTimeCell
}, { },
{
name : 'nextExecution', name : 'nextExecution',
label : 'Next Execution', label : 'Next Execution',
sortable : true, sortable : true,
cell : NextExecutionCell cell : NextExecutionCell
}, { },
{
name : 'this', name : 'this',
label : '', label : '',
sortable : false, sortable : false,
cell : ExecuteTaskCell cell : ExecuteTaskCell
}], }
],
initialize : function() { initialize : function() {
this.taskCollection = new BackupCollection(); this.taskCollection = new BackupCollection();
this.listenTo(this.taskCollection, 'sync', this._showTasks); this.listenTo(this.taskCollection, 'sync', this._showTasks);
this.taskCollection.bindSignalR(); this.taskCollection.bindSignalR();
}, },
onRender : function() { onRender : function() {
this.tasks.show(new LoadingView()); this.tasks.show(new LoadingView());
this.taskCollection.fetch(); this.taskCollection.fetch();
}, },
_showTasks : function() { _showTasks : function() {
this.tasks.show(new Backgrid.Grid({ this.tasks.show(new Backgrid.Grid({
columns : this.columns, columns : this.columns,

@ -1,3 +1,5 @@
var Marionette = require('marionette'); var Marionette = require('marionette');
module.exports = Marionette.ItemView.extend({template : 'System/Update/EmptyViewTemplate'}); module.exports = Marionette.ItemView.extend({
template : 'System/Update/EmptyViewTemplate'
});

@ -3,17 +3,25 @@ var CommandController = require('../../Commands/CommandController');
module.exports = Marionette.ItemView.extend({ module.exports = Marionette.ItemView.extend({
template : 'System/Update/UpdateItemViewTemplate', template : 'System/Update/UpdateItemViewTemplate',
events : {"click .x-install-update" : '_installUpdate'},
events : {
'click .x-install-update' : '_installUpdate'
},
initialize : function() { initialize : function() {
this.updating = false; this.updating = false;
}, },
_installUpdate : function() { _installUpdate : function() {
if (this.updating) { if (this.updating) {
return; return;
} }
this.updating = true; this.updating = true;
var self = this; var self = this;
var promise = CommandController.Execute('applicationUpdate'); var promise = CommandController.Execute('applicationUpdate');
promise.done(function() { promise.done(function() {
window.setTimeout(function() { window.setTimeout(function() {
self.updating = false; self.updating = false;

@ -6,15 +6,23 @@ var LoadingView = require('../../Shared/LoadingView');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'System/Update/UpdateLayoutTemplate', template : 'System/Update/UpdateLayoutTemplate',
regions : {updates : '#x-updates'},
regions : {
updates : '#x-updates'
},
initialize : function() { initialize : function() {
this.updateCollection = new UpdateCollection(); this.updateCollection = new UpdateCollection();
this.listenTo(this.updateCollection, 'sync', this._showUpdates); this.listenTo(this.updateCollection, 'sync', this._showUpdates);
}, },
onRender : function() { onRender : function() {
this.updates.show(new LoadingView()); this.updates.show(new LoadingView());
this.updateCollection.fetch(); this.updateCollection.fetch();
}, },
_showUpdates : function() { _showUpdates : function() {
this.updates.show(new UpdateCollectionView({ collection : this.updateCollection })); this.updates.show(new UpdateCollectionView({ collection : this.updateCollection }));
} }

@ -2,9 +2,7 @@
var TagModel = require('./TagModel'); var TagModel = require('./TagModel');
var ApiData = require('../Shared/ApiData'); var ApiData = require('../Shared/ApiData');
require('../Mixins/backbone.signalr.mixin'); var Collection = Backbone.Collection.extend({
var collection = Backbone.Collection.extend({
url : window.NzbDrone.ApiRoot + '/tag', url : window.NzbDrone.ApiRoot + '/tag',
model : TagModel, model : TagModel,
@ -13,4 +11,4 @@ var collection = Backbone.Collection.extend({
} }
}); });
module.exports = new collection(ApiData.get('tag')).bindSignalR(); module.exports = new Collection(ApiData.get('tag'));

@ -2,22 +2,24 @@ var _ = require('underscore');
var Handlebars = require('handlebars'); var Handlebars = require('handlebars');
var TagCollection = require('./TagCollection'); var TagCollection = require('./TagCollection');
module.exports = (function(){
Handlebars.registerHelper('tagDisplay', function(tags) { Handlebars.registerHelper('tagDisplay', function(tags) {
var tagLabels = _.map(TagCollection.filter(function(tag) { var tagLabels = _.map(TagCollection.filter(function(tag) {
return _.contains(tags, tag.get('id')); return _.contains(tags, tag.get('id'));
}), function(tag) { }), function(tag) {
return '<span class="label label-info">{0}</span>'.format(tag.get('label')); return '<span class="label label-info">{0}</span>'.format(tag.get('label'));
}); });
return new Handlebars.SafeString(tagLabels.join(' ')); return new Handlebars.SafeString(tagLabels.join(' '));
}); });
Handlebars.registerHelper('genericTagDisplay', function(tags, classes) { Handlebars.registerHelper('genericTagDisplay', function(tags, classes) {
if (!tags) { if (!tags) {
return new Handlebars.SafeString(''); return new Handlebars.SafeString('');
} }
var tagLabels = _.map(tags.split(','), function(tag) { var tagLabels = _.map(tags.split(','), function(tag) {
return '<span class="{0}">{1}</span>'.format(classes, tag); return '<span class="{0}">{1}</span>'.format(classes, tag);
}); });
return new Handlebars.SafeString(tagLabels.join(' ')); return new Handlebars.SafeString(tagLabels.join(' '));
}); });
}).call(this);

@ -5,16 +5,17 @@ var AsFilteredCollection = require('../../Mixins/AsFilteredCollection');
var AsSortedCollection = require('../../Mixins/AsSortedCollection'); var AsSortedCollection = require('../../Mixins/AsSortedCollection');
var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollection'); var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollection');
module.exports = (function(){
var Collection = PagableCollection.extend({ var Collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/wanted/cutoff', url : window.NzbDrone.ApiRoot + '/wanted/cutoff',
model : EpisodeModel, model : EpisodeModel,
tableName : 'wanted.cutoff', tableName : 'wanted.cutoff',
state : { state : {
pageSize : 15, pageSize : 15,
sortKey : 'airDateUtc', sortKey : 'airDateUtc',
order : 1 order : 1
}, },
queryParams : { queryParams : {
totalPages : null, totalPages : null,
totalRecords : null, totalRecords : null,
@ -22,26 +23,41 @@ module.exports = (function(){
sortKey : 'sortKey', sortKey : 'sortKey',
order : 'sortDir', order : 'sortDir',
directions : { directions : {
"-1" : 'asc', '-1' : 'asc',
"1" : 'desc' '1' : 'desc'
} }
}, },
// Filter Modes
filterModes : { filterModes : {
"monitored" : ['monitored', 'true'], 'monitored' : [
"unmonitored" : ['monitored', 'false'] 'monitored',
'true'
],
'unmonitored' : [
'monitored',
'false'
],
},
sortMappings : {
'series' : { sortKey : 'series.sortTitle' }
}, },
sortMappings : {"series" : {sortKey : 'series.sortTitle'}},
parseState : function(resp) { parseState : function(resp) {
return { totalRecords : resp.totalRecords }; return { totalRecords : resp.totalRecords };
}, },
parseRecords : function(resp) { parseRecords : function(resp) {
if (resp) { if (resp) {
return resp.records; return resp.records;
} }
return resp; return resp;
} }
}); });
Collection = AsFilteredCollection.call(Collection); Collection = AsFilteredCollection.call(Collection);
Collection = AsSortedCollection.call(Collection); Collection = AsSortedCollection.call(Collection);
return AsPersistedStateCollection.call(Collection);
}).call(this); module.exports = AsPersistedStateCollection.call(Collection);

@ -17,126 +17,168 @@ require('../../Mixins/backbone.signalr.mixin');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'Wanted/Cutoff/CutoffUnmetLayoutTemplate', template : 'Wanted/Cutoff/CutoffUnmetLayoutTemplate',
regions : { regions : {
cutoff : '#x-cutoff-unmet', cutoff : '#x-cutoff-unmet',
toolbar : '#x-toolbar', toolbar : '#x-toolbar',
pager : '#x-pager' pager : '#x-pager'
}, },
ui : {searchSelectedButton : '.btn i.icon-search'},
columns : [{ ui : {
searchSelectedButton : '.btn i.icon-search'
},
columns : [
{
name : '', name : '',
cell : 'select-row', cell : 'select-row',
headerCell : 'select-all', headerCell : 'select-all',
sortable : false sortable : false
}, { },
{
name : 'series', name : 'series',
label : 'Series Title', label : 'Series Title',
cell : SeriesTitleCell, cell : SeriesTitleCell,
sortValue : 'series.sortTitle' sortValue : 'series.sortTitle'
}, { },
{
name : 'this', name : 'this',
label : 'Episode', label : 'Episode',
cell : EpisodeNumberCell, cell : EpisodeNumberCell,
sortable : false sortable : false
}, { },
{
name : 'this', name : 'this',
label : 'Episode Title', label : 'Episode Title',
cell : EpisodeTitleCell, cell : EpisodeTitleCell,
sortable : false sortable : false
}, { },
{
name : 'airDateUtc', name : 'airDateUtc',
label : 'Air Date', label : 'Air Date',
cell : RelativeDateCell cell : RelativeDateCell
}, { },
{
name : 'status', name : 'status',
label : 'Status', label : 'Status',
cell : EpisodeStatusCell, cell : EpisodeStatusCell,
sortable : false sortable : false
}], }
],
initialize : function() { initialize : function() {
this.collection = new CutoffUnmetCollection().bindSignalR({ updateOnly : true }); this.collection = new CutoffUnmetCollection().bindSignalR({ updateOnly : true });
this.listenTo(this.collection, 'sync', this._showTable); this.listenTo(this.collection, 'sync', this._showTable);
}, },
onShow : function() { onShow : function() {
this.cutoff.show(new LoadingView()); this.cutoff.show(new LoadingView());
this._showToolbar(); this._showToolbar();
this.collection.fetch(); this.collection.fetch();
}, },
_showTable : function() { _showTable : function() {
this.cutoffGrid = new Backgrid.Grid({ this.cutoffGrid = new Backgrid.Grid({
columns : this.columns, columns : this.columns,
collection : this.collection, collection : this.collection,
className : 'table table-hover' className : 'table table-hover'
}); });
this.cutoff.show(this.cutoffGrid); this.cutoff.show(this.cutoffGrid);
this.pager.show(new GridPager({ this.pager.show(new GridPager({
columns : this.columns, columns : this.columns,
collection : this.collection collection : this.collection
})); }));
}, },
_showToolbar : function() { _showToolbar : function() {
var leftSideButtons = { var leftSideButtons = {
type : 'default', type : 'default',
storeState : false, storeState : false,
items : [{ items : [
{
title : 'Search Selected', title : 'Search Selected',
icon : 'icon-search', icon : 'icon-search',
callback : this._searchSelected, callback : this._searchSelected,
ownerContext : this, ownerContext : this,
className : 'x-search-selected' className : 'x-search-selected'
}, { },
{
title : 'Season Pass', title : 'Season Pass',
icon : 'icon-bookmark', icon : 'icon-bookmark',
route : 'seasonpass' route : 'seasonpass'
}] }
]
}; };
var filterOptions = { var filterOptions = {
type : 'radio', type : 'radio',
storeState : false, storeState : false,
menuKey : 'wanted.filterMode', menuKey : 'wanted.filterMode',
defaultAction : 'monitored', defaultAction : 'monitored',
items : [{ items : [
{
key : 'monitored', key : 'monitored',
title : '', title : '',
tooltip : 'Monitored Only', tooltip : 'Monitored Only',
icon : 'icon-nd-monitored', icon : 'icon-nd-monitored',
callback : this._setFilter callback : this._setFilter
}, { },
{
key : 'unmonitored', key : 'unmonitored',
title : '', title : '',
tooltip : 'Unmonitored Only', tooltip : 'Unmonitored Only',
icon : 'icon-nd-unmonitored', icon : 'icon-nd-unmonitored',
callback : this._setFilter callback : this._setFilter
}] }
]
}; };
this.toolbar.show(new ToolbarLayout({ this.toolbar.show(new ToolbarLayout({
left : [leftSideButtons], left : [
right : [filterOptions], leftSideButtons
],
right : [
filterOptions
],
context : this context : this
})); }));
CommandController.bindToCommand({ CommandController.bindToCommand({
element : this.$('.x-search-selected'), element : this.$('.x-search-selected'),
command : {name : 'episodeSearch'} command : {
name : 'episodeSearch'
}
}); });
}, },
_setFilter : function(buttonContext) { _setFilter : function(buttonContext) {
var mode = buttonContext.model.get('key'); var mode = buttonContext.model.get('key');
this.collection.state.currentPage = 1; this.collection.state.currentPage = 1;
var promise = this.collection.setFilterMode(mode); var promise = this.collection.setFilterMode(mode);
if (buttonContext) { if (buttonContext) {
buttonContext.ui.icon.spinForPromise(promise); buttonContext.ui.icon.spinForPromise(promise);
} }
}, },
_searchSelected : function() { _searchSelected : function() {
var selected = this.cutoffGrid.getSelectedModels(); var selected = this.cutoffGrid.getSelectedModels();
if (selected.length === 0) { if (selected.length === 0) {
Messenger.show({ Messenger.show({
type : 'error', type : 'error',
message : 'No episodes selected' message : 'No episodes selected'
}); });
return; return;
} }
var ids = _.pluck(selected, 'id'); var ids = _.pluck(selected, 'id');
CommandController.Execute('episodeSearch', { CommandController.Execute('episodeSearch', {
name : 'episodeSearch', name : 'episodeSearch',
episodeIds : ids episodeIds : ids

@ -5,16 +5,17 @@ var AsFilteredCollection = require('../../Mixins/AsFilteredCollection');
var AsSortedCollection = require('../../Mixins/AsSortedCollection'); var AsSortedCollection = require('../../Mixins/AsSortedCollection');
var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollection'); var AsPersistedStateCollection = require('../../Mixins/AsPersistedStateCollection');
module.exports = (function(){
var Collection = PagableCollection.extend({ var Collection = PagableCollection.extend({
url : window.NzbDrone.ApiRoot + '/wanted/missing', url : window.NzbDrone.ApiRoot + '/wanted/missing',
model : EpisodeModel, model : EpisodeModel,
tableName : 'wanted.missing', tableName : 'wanted.missing',
state : { state : {
pageSize : 15, pageSize : 15,
sortKey : 'airDateUtc', sortKey : 'airDateUtc',
order : 1 order : 1
}, },
queryParams : { queryParams : {
totalPages : null, totalPages : null,
totalRecords : null, totalRecords : null,
@ -22,26 +23,39 @@ module.exports = (function(){
sortKey : 'sortKey', sortKey : 'sortKey',
order : 'sortDir', order : 'sortDir',
directions : { directions : {
"-1" : 'asc', '-1' : 'asc',
"1" : 'desc' '1' : 'desc'
} }
}, },
filterModes : { filterModes : {
"monitored" : ['monitored', 'true'], 'monitored' : [
"unmonitored" : ['monitored', 'false'] 'monitored',
'true'
],
'unmonitored' : [
'monitored',
'false'
]
},
sortMappings : {
'series' : { sortKey : 'series.sortTitle' }
}, },
sortMappings : {"series" : {sortKey : 'series.sortTitle'}},
parseState : function(resp) { parseState : function(resp) {
return { totalRecords : resp.totalRecords }; return { totalRecords : resp.totalRecords };
}, },
parseRecords : function(resp) { parseRecords : function(resp) {
if (resp) { if (resp) {
return resp.records; return resp.records;
} }
return resp; return resp;
} }
}); });
Collection = AsFilteredCollection.call(Collection); Collection = AsFilteredCollection.call(Collection);
Collection = AsSortedCollection.call(Collection); Collection = AsSortedCollection.call(Collection);
return AsPersistedStateCollection.call(Collection);
}).call(this); module.exports = AsPersistedStateCollection.call(Collection);

@ -17,109 +17,137 @@ require('../../Mixins/backbone.signalr.mixin');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'Wanted/Missing/MissingLayoutTemplate', template : 'Wanted/Missing/MissingLayoutTemplate',
regions : { regions : {
missing : '#x-missing', missing : '#x-missing',
toolbar : '#x-toolbar', toolbar : '#x-toolbar',
pager : '#x-pager' pager : '#x-pager'
}, },
ui : {searchSelectedButton : '.btn i.icon-search'},
columns : [{ ui : {
searchSelectedButton : '.btn i.icon-search'
},
columns : [
{
name : '', name : '',
cell : 'select-row', cell : 'select-row',
headerCell : 'select-all', headerCell : 'select-all',
sortable : false sortable : false
}, { },
{
name : 'series', name : 'series',
label : 'Series Title', label : 'Series Title',
cell : SeriesTitleCell, cell : SeriesTitleCell,
sortValue : 'series.sortTitle' sortValue : 'series.sortTitle'
}, { },
{
name : 'this', name : 'this',
label : 'Episode', label : 'Episode',
cell : EpisodeNumberCell, cell : EpisodeNumberCell,
sortable : false sortable : false
}, { },
{
name : 'this', name : 'this',
label : 'Episode Title', label : 'Episode Title',
cell : EpisodeTitleCell, cell : EpisodeTitleCell,
sortable : false sortable : false
}, { },
{
name : 'airDateUtc', name : 'airDateUtc',
label : 'Air Date', label : 'Air Date',
cell : RelativeDateCell cell : RelativeDateCell
}, { },
{
name : 'status', name : 'status',
label : 'Status', label : 'Status',
cell : EpisodeStatusCell, cell : EpisodeStatusCell,
sortable : false sortable : false
}], }
],
initialize : function() { initialize : function() {
this.collection = new MissingCollection().bindSignalR({ updateOnly : true }); this.collection = new MissingCollection().bindSignalR({ updateOnly : true });
this.listenTo(this.collection, 'sync', this._showTable); this.listenTo(this.collection, 'sync', this._showTable);
}, },
onShow : function() { onShow : function() {
this.missing.show(new LoadingView()); this.missing.show(new LoadingView());
this._showToolbar(); this._showToolbar();
this.collection.fetch(); this.collection.fetch();
}, },
_showTable : function() { _showTable : function() {
this.missingGrid = new Backgrid.Grid({ this.missingGrid = new Backgrid.Grid({
columns : this.columns, columns : this.columns,
collection : this.collection, collection : this.collection,
className : 'table table-hover' className : 'table table-hover'
}); });
this.missing.show(this.missingGrid); this.missing.show(this.missingGrid);
this.pager.show(new GridPager({ this.pager.show(new GridPager({
columns : this.columns, columns : this.columns,
collection : this.collection collection : this.collection
})); }));
}, },
_showToolbar : function() { _showToolbar : function() {
var leftSideButtons = { var leftSideButtons = {
type : 'default', type : 'default',
storeState : false, storeState : false,
collapse : true, collapse : true,
items : [{ items : [
{
title : 'Search Selected', title : 'Search Selected',
icon : 'icon-search', icon : 'icon-search',
callback : this._searchSelected, callback : this._searchSelected,
ownerContext : this, ownerContext : this,
className : 'x-search-selected' className : 'x-search-selected'
}, { },
{
title : 'Search All Missing', title : 'Search All Missing',
icon : 'icon-search', icon : 'icon-search',
callback : this._searchMissing, callback : this._searchMissing,
ownerContext : this, ownerContext : this,
className : 'x-search-missing' className : 'x-search-missing'
}, { },
{
title : 'Season Pass', title : 'Season Pass',
icon : 'icon-bookmark', icon : 'icon-bookmark',
route : 'seasonpass' route : 'seasonpass'
}, { },
{
title : 'Rescan Drone Factory Folder', title : 'Rescan Drone Factory Folder',
icon : 'icon-refresh', icon : 'icon-refresh',
command : 'downloadedepisodesscan', command : 'downloadedepisodesscan',
properties : { sendUpdates : true } properties : { sendUpdates : true }
}] }
]
}; };
var filterOptions = { var filterOptions = {
type : 'radio', type : 'radio',
storeState : false, storeState : false,
menuKey : 'wanted.filterMode', menuKey : 'wanted.filterMode',
defaultAction : 'monitored', defaultAction : 'monitored',
items : [{ items : [
{
key : 'monitored', key : 'monitored',
title : '', title : '',
tooltip : 'Monitored Only', tooltip : 'Monitored Only',
icon : 'icon-nd-monitored', icon : 'icon-nd-monitored',
callback : this._setFilter callback : this._setFilter
}, { },
{
key : 'unmonitored', key : 'unmonitored',
title : '', title : '',
tooltip : 'Unmonitored Only', tooltip : 'Unmonitored Only',
icon : 'icon-nd-unmonitored', icon : 'icon-nd-unmonitored',
callback : this._setFilter callback : this._setFilter
}] }
]
}; };
this.toolbar.show(new ToolbarLayout({ this.toolbar.show(new ToolbarLayout({
left : [leftSideButtons], left : [leftSideButtons],
@ -159,7 +187,8 @@ module.exports = Marionette.Layout.extend({
}); });
}, },
_searchMissing : function() { _searchMissing : function() {
if(window.confirm('Are you sure you want to search for {0} missing episodes? '.format(this.collection.state.totalRecords) + 'One API request to each indexer will be used for each episode. ' + 'This cannot be stopped once started.')) { if (window.confirm('Are you sure you want to search for {0} missing episodes? '.format(this.collection.state.totalRecords) +
'One API request to each indexer will be used for each episode. ' + 'This cannot be stopped once started.')) {
CommandController.Execute('missingEpisodeSearch', { name : 'missingEpisodeSearch' }); CommandController.Execute('missingEpisodeSearch', { name : 'missingEpisodeSearch' });
} }
} }

@ -6,20 +6,29 @@ var CutoffUnmetLayout = require('./Cutoff/CutoffUnmetLayout');
module.exports = Marionette.Layout.extend({ module.exports = Marionette.Layout.extend({
template : 'Wanted/WantedLayoutTemplate', template : 'Wanted/WantedLayoutTemplate',
regions : {content : '#content'},
regions : {
content : '#content'
//missing : '#missing',
//cutoff : '#cutoff'
},
ui : { ui : {
missingTab : '.x-missing-tab', missingTab : '.x-missing-tab',
cutoffTab : '.x-cutoff-tab' cutoffTab : '.x-cutoff-tab'
}, },
events : { events : {
"click .x-missing-tab" : '_showMissing', 'click .x-missing-tab' : '_showMissing',
"click .x-cutoff-tab" : '_showCutoffUnmet' 'click .x-cutoff-tab' : '_showCutoffUnmet'
}, },
initialize : function(options) { initialize : function(options) {
if (options.action) { if (options.action) {
this.action = options.action.toLowerCase(); this.action = options.action.toLowerCase();
} }
}, },
onShow : function() { onShow : function() {
switch (this.action) { switch (this.action) {
case 'cutoff': case 'cutoff':
@ -29,24 +38,29 @@ module.exports = Marionette.Layout.extend({
this._showMissing(); this._showMissing();
} }
}, },
_navigate : function(route) { _navigate : function(route) {
Backbone.history.navigate(route, { Backbone.history.navigate(route, {
trigger : false, trigger : false,
replace : true replace : true
}); });
}, },
_showMissing : function(e) { _showMissing : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.content.show(new MissingLayout()); this.content.show(new MissingLayout());
this.ui.missingTab.tab('show'); this.ui.missingTab.tab('show');
this._navigate('/wanted/missing'); this._navigate('/wanted/missing');
}, },
_showCutoffUnmet : function(e) { _showCutoffUnmet : function(e) {
if (e) { if (e) {
e.preventDefault(); e.preventDefault();
} }
this.content.show(new CutoffUnmetLayout()); this.content.show(new CutoffUnmetLayout());
this.ui.cutoffTab.tab('show'); this.ui.cutoffTab.tab('show');
this._navigate('/wanted/cutoff'); this._navigate('/wanted/cutoff');

Loading…
Cancel
Save