Sorting of tasks and nodes in admin panel.

This commit is contained in:
baldo 2016-06-07 11:58:29 +02:00
parent ce2359a094
commit 954b7a3920
7 changed files with 77 additions and 21 deletions

View file

@ -35,6 +35,8 @@ angular.module('ffffngAdmin').config(function(NgAdminConfigurationProvider, Cons
.listView() .listView()
.title('Nodes') .title('Nodes')
.perPage(30) .perPage(30)
.sortDir('ASC')
.sortField('hostname')
.actions([]) .actions([])
.batchActions([]) .batchActions([])
.exportFields([]) .exportFields([])
@ -52,13 +54,17 @@ angular.module('ffffngAdmin').config(function(NgAdminConfigurationProvider, Cons
? '<i class="fa fa-map-marker coords-set" aria-hidden="true" title="coordinates set"></i>' ? '<i class="fa fa-map-marker coords-set" aria-hidden="true" title="coordinates set"></i>'
: '<i class="fa fa-times coords-unset" aria-hidden="true" title="no coordinates"></i>'; : '<i class="fa fa-times coords-unset" aria-hidden="true" title="no coordinates"></i>';
}), }),
nga.field('monitoring').cssClasses(nodeClasses).template(function (node) { nga.field('monitoringState').cssClasses(nodeClasses).template(function (node) {
if (!node.values.monitoring) { switch (node.values.monitoringState) {
return '<i class="fa fa-times monitoring-disabled" title="disabled"></i>'; case 'active':
return '<i class="fa fa-check monitoring-active" title="active"></i>';
case 'pending':
return '<i class="fa fa-envelope monitoring-confirmation-pending" title="confirmation pending"></i>';
default:
return '<i class="fa fa-times monitoring-disabled" title="disabled"></i>';
} }
return node.values.monitoringConfirmed
? '<i class="fa fa-check monitoring-active" title="active"></i>'
: '<i class="fa fa-envelope monitoring-confirmation-pending" title="confirmation pending"></i>';
}) })
]) ])
.listActions([ .listActions([
@ -104,6 +110,8 @@ angular.module('ffffngAdmin').config(function(NgAdminConfigurationProvider, Cons
.listView() .listView()
.title('Background-Jobs') .title('Background-Jobs')
.perPage(30) .perPage(30)
.sortDir('ASC')
.sortField('id')
.actions([]) .actions([])
.batchActions([]) .batchActions([])
.exportFields([]) .exportFields([])

View file

@ -100,15 +100,22 @@ angular.module('ffffng').factory('NodeResource', function (
return Resources.error(res, err); return Resources.error(res, err);
} }
// TODO: Sort + Filter // TODO: Filter
return NodeService.getAllNodes(restParams._page, restParams._perPage, function (err, nodes, total) { return NodeService.getAllNodes(function (err, nodes, total) {
if (err) { if (err) {
return Resources.error(res, err); return Resources.error(res, err);
} }
var sortedNodes = Resources.sort(
nodes,
['token', 'mac', 'hostname', 'key', 'coords', 'monitoringState'],
restParams
);
var pageNodes = Resources.getPageEntities(sortedNodes, restParams);
res.set('X-Total-Count', total); res.set('X-Total-Count', total);
return Resources.success(res, nodes); return Resources.success(res, pageNodes);
}); });
}); });
} }

View file

@ -79,15 +79,14 @@ angular.module('ffffng').factory('TaskResource', function (
return Resources.error(res, err); return Resources.error(res, err);
} }
// TODO: Sort var tasks = Resources.sort(
_.values(Scheduler.getTasks()),
var tasks = _.values(Scheduler.getTasks()); ['id', 'name', 'schedule', 'state', 'runningSince', 'lastRunStarted'],
restParams
);
var total = tasks.length; var total = tasks.length;
var page = restParams._page; var pageTasks = Resources.getPageEntities(tasks, restParams);
var perPage = restParams._perPage;
var pageTasks = tasks.slice((page - 1) * perPage, page * perPage);
res.set('X-Total-Count', total); res.set('X-Total-Count', total);
return Resources.success(res, _.map(pageTasks, toExternalTask)); return Resources.success(res, _.map(pageTasks, toExternalTask));

View file

@ -217,6 +217,7 @@ angular.module('ffffng')
var pending = value === 'pending'; var pending = value === 'pending';
node.monitoring = active || pending; node.monitoring = active || pending;
node.monitoringConfirmed = active; node.monitoringConfirmed = active;
node.monitoringState = active ? 'active' : (pending ? 'pending' : '');
} else if (key === 'monitoringToken') { } else if (key === 'monitoringToken') {
nodeSecrets.monitoringToken = value; nodeSecrets.monitoringToken = value;
} else { } else {
@ -369,13 +370,12 @@ angular.module('ffffng')
deleteNodeFile(token, callback); deleteNodeFile(token, callback);
}, },
getAllNodes: function (page, perPage, callback) { getAllNodes: function (callback) {
var files = _.sortBy(findNodeFiles({})); var files = findNodeFiles({});
var total = files.length; var total = files.length;
var pageFiles = files.slice((page - 1) * perPage, page * perPage);
async.mapLimit( async.mapLimit(
pageFiles, files,
MAX_PARALLEL_NODES_PARSING, MAX_PARALLEL_NODES_PARSING,
parseNodeFile, parseNodeFile,
function (err, nodes) { function (err, nodes) {

View file

@ -36,6 +36,24 @@ angular.module('ffffng').factory('Resources', function (_, Constraints, Validato
callback(null, restParams); callback(null, restParams);
}, },
sort: function (entities, allowedSortFields, restParams) {
var sortField = _.indexOf(allowedSortFields, restParams._sortField) >= 0 ? restParams._sortField : undefined;
if (!sortField) {
return entities;
}
var sorted = _.sortBy(entities, [sortField]);
return restParams._sortDir === 'ASC' ? sorted : _.reverse(sorted);
},
getPageEntities: function (entities, restParams) {
var page = restParams._page;
var perPage = restParams._perPage;
return entities.slice((page - 1) * perPage, page * perPage);
},
success: function (res, data) { success: function (res, data) {
respond(res, 200, data); respond(res, 200, data);
}, },

View file

@ -1,8 +1,10 @@
'use strict'; 'use strict';
angular.module('ffffng').factory('Validator', function (_, Strings, Logger) { angular.module('ffffng').factory('Validator', function (_, Strings, Logger) {
// TODO: sanitize input for further processing as specified by constraints (correct types, trimming, etc.)
function isValidBoolean(value) { function isValidBoolean(value) {
return _.isBoolean(value); return _.isBoolean(value) || value === 'true' || value === 'false';
} }
function isValidNumber(constraint, value) { function isValidNumber(constraint, value) {
@ -29,6 +31,14 @@ angular.module('ffffng').factory('Validator', function (_, Strings, Logger) {
return true; return true;
} }
function isValidEnum(constraint, value) {
if (!_.isString(value)) {
return false;
}
return _.indexOf(constraint.allowed, value) >= 0;
}
function isValidString(constraint, value) { function isValidString(constraint, value) {
if (!_.isString(value)) { if (!_.isString(value)) {
return false; return false;
@ -50,6 +60,9 @@ angular.module('ffffng').factory('Validator', function (_, Strings, Logger) {
case 'number': case 'number':
return isValidNumber(constraint, value); return isValidNumber(constraint, value);
case 'enum':
return isValidEnum(constraint, value);
case 'string': case 'string':
return isValidString(constraint, value); return isValidString(constraint, value);
} }

View file

@ -61,6 +61,17 @@ angular.module('ffffng').constant('Constraints', {
max: 50, max: 50,
optional: true, optional: true,
default: 20 default: 20
},
_sortDir: {
type: 'enum',
allowed: ['ASC', 'DESC'],
optional: true,
default: 'ASC'
},
_sortField: {
type: 'string',
regex: /^[a-zA-Z0-9_]{1,32}$/,
optional: true
} }
} }
} }