Merge pull request #16 from Freddrickk/paramTable

Modify project layout and parametrizable table
This commit is contained in:
Frédéric Vachon 2015-02-06 14:49:35 -05:00
commit d843ce4835
55 changed files with 359 additions and 98 deletions

View File

@ -56,6 +56,7 @@ module.exports = function (grunt) {
unparam: true, // TEMPORARY: Ignore unused params
nomen: true,
predef: [ // Global variables
'document', '$', '$get',
'angular', 'inject', 'JustGage',
'describe', 'beforeEach', 'it', 'expect',
'moment'

View File

@ -1,12 +1,28 @@
'use strict';
angular.element(document).ready(function () {
$.get('components/config/config.json', function (data) {
angular.module('adagios.config').config(['readConfigProvider', function (readConfigProvider) {
readConfigProvider.setDashboardConfig(data.dashboardConfig);
readConfigProvider.setHostsConfig(data.hostsConfig);
}]);
angular.bootstrap(document, ['adagios']);
}, "json");
});
angular.module('adagios', [
'ngRoute',
'adagios.sidebar',
'adagios.topbar',
'adagios.tactical',
'adagios.table',
'adagios.filters'
'adagios.filters',
'adagios.config',
'adagios.view.hosts'
])
.config(['$routeProvider', function ($routeProvider) {

View File

@ -57,9 +57,9 @@ $fa-font-path: '../../bower_components/fontawesome/fonts' !default;
//----------------------------------*\
// INTERFACE MODULES
//----------------------------------*/
@import '../../topbar/topbar';
@import '../../sidebar/sidebar';
@import '../../tactical/tactical';
@import '../../components/topbar/topbar';
@import '../../components/sidebar/sidebar';
@import '../../components/tactical/tactical';
/* body:before { */
/* display:none; */

View File

@ -0,0 +1,27 @@
'use strict';
function AdagiosConfig(dashboardConfig, hostsConfig) {
this.dashboardConfig = dashboardConfig;
this.hostsConfig = hostsConfig;
}
angular.module('adagios.config', [])
.provider('readConfig', function ReadConfigProvider() {
var dashboardConfig = {},
hostsConfig = {};
this.setDashboardConfig = function (value) {
dashboardConfig = value;
};
this.setHostsConfig = function (value) {
hostsConfig = value;
};
this.$get = [function getConfigFactory() {
return new AdagiosConfig(dashboardConfig, hostsConfig);
}];
});

View File

@ -0,0 +1,12 @@
{
"dashboardConfig": {
"cells": ["host", "service_check", "duration", "last_check"],
"apiName": "services",
"filters": { "isnot": { "host_state": ["0"]} }
},
"hostsConfig": {
"cells": ["hosts_host", "host_address", "duration", "last_check", "host_status"],
"apiName": "hosts",
"filters": {}
}
}

View File

@ -8,12 +8,13 @@ angular.module('adagios.live')
endswith: '__endswith',
exists: '__exists',
in: '__in',
isnot: '__isnot',
regex: '__regex'
})
.factory('getServices', ['$http', 'filterSuffixes',
function ($http, filterSuffixes, columns, filters) {
return function (columns, filters) {
function ($http, filterSuffixes, columns, filters, apiName) {
return function (columns, filters, apiName) {
var filtersQuery = '';
function createFiltersQuery(filters) {
@ -34,7 +35,7 @@ angular.module('adagios.live')
filtersQuery = createFiltersQuery(filters);
return $http.get('/rest/status/json/services/?fields=' + columns + filtersQuery)
return $http.get('/rest/status/json/' + apiName + '/?fields=' + columns + filtersQuery)
.error(function (data, status, headers, config) {
console.error('getServices : GET Request failed');
});

View File

@ -14,9 +14,10 @@ describe('In Adagios Live', function () {
it('should send the proper GET request', inject(function (getServices) {
var fields = ['host_name', 'host_state', 'description'],
filters = { contains: { host_name: ['srv', 'a'], plugin_output: ['SWAP'] },
startswith: { host_name: ['srv'] } };
startswith: { host_name: ['srv'] } },
apiName = 'services';
getServices(fields, filters);
getServices(fields, filters, apiName);
$httpBackend.expectGET('/rest/status/json/services/?fields=host_name,host_state,description&host_name__contains=srv&host_name__contains=a&plugin_output__contains=SWAP&host_name__startswith=srv').respond('');
$httpBackend.flush();
}));

View File

@ -6,7 +6,7 @@
<li class="menu-title">
<a href="#"> Shortcut <span class="arrow"></span></a>
<ul class="sub-menu" id="shortcut">
<li><a href="#/tactical">Dashboard</a></li>
<li><a href="#/dashboard">Dashboard</a></li>
<li><a href="#/hosts">Hosts</a></li>
<li><a href="#">Services</a></li>
<li><a href="#">Networks parents</a></li>

View File

@ -9,6 +9,6 @@ angular.module('adagios.sidebar', [])
.directive('adgSidebar', function () {
return {
restrict: 'E',
templateUrl: "sidebar/sidebar.html"
templateUrl: "components/sidebar/sidebar.html"
};
});

View File

@ -14,7 +14,7 @@ describe('Sidebar module', function () {
$controller = _$controller_;
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('sidebar/sidebar.html').respond('<li></li>');
$httpBackend.expectGET('components/sidebar/sidebar.html').respond('<li></li>');
}));
describe('SideBarCtrl', function () {

View File

@ -0,0 +1,11 @@
'use strict';
angular.module('adagios.table.cell_duration', ['adagios.table'])
.controller('CellDurationCtrl', ['$scope', function ($scope) {
angular.noop();
}])
.run(['tableConfig', function (tableConfig) {
tableConfig.cellToFieldsMap.duration = ['last_state_change'];
}]);

View File

@ -0,0 +1,11 @@
'use strict';
angular.module('adagios.table.cell_host', ['adagios.table'])
.controller('CellHostCtrl', ['$scope', function ($scope) {
angular.noop();
}])
.run(['tableConfig', function (tableConfig) {
tableConfig.cellToFieldsMap.host = [ 'host_state', 'host_name' ];
}]);

View File

@ -0,0 +1 @@
<div ng-controller="CellHostAddressCtrl">{{entry.address}}</div>

View File

@ -0,0 +1,11 @@
'use strict';
angular.module('adagios.table.cell_host_address', ['adagios.table'])
.controller('CellHostAddressCtrl', ['$scope', function ($scope) {
angular.noop();
}])
.run(['tableConfig', function (tableConfig) {
tableConfig.cellToFieldsMap.host_address = ['host_address'];
}]);

View File

@ -0,0 +1 @@
<div class="{{alert_level}}" ng-controller="CellHostStatusCtrl">{{entry.host_status}}</div>

View File

@ -0,0 +1,28 @@
'use strict';
angular.module('adagios.table.cell_host_status', ['adagios.table'])
.controller('CellHostStatusCtrl', ['$scope', function ($scope) {
$scope.entry.host_status = "";
$scope.alert_level = "";
if ($scope.entry.last_check === 0) {
$scope.alert_level = "alert alert-info";
$scope.entry.host_status = "Pending";
} else if ($scope.entry.state === 0) {
$scope.alert_level = "alert alert-success";
$scope.entry.host_status = "Host UP";
} else {
$scope.alert_level = "alert alert-danger";
if ($scope.entry.childs.length !== 0) {
$scope.entry.host_status = "Network outage";
} else {
$scope.entry.host_status = "Host down";
}
}
}])
.run(['tableConfig', function (tableConfig) {
tableConfig.cellToFieldsMap.host_status = ['state', 'last_check', 'childs'];
}]);

View File

@ -0,0 +1 @@
<div ng-controller="CellHostsHostCtrl">{{entry.name}}</div>

View File

@ -0,0 +1,11 @@
'use strict';
angular.module('adagios.table.cell_hosts_host', ['adagios.table'])
.controller('CellHostsHostCtrl', ['$scope', function ($scope) {
angular.noop();
}])
.run(['tableConfig', function (tableConfig) {
tableConfig.cellToFieldsMap.hosts_host = ['name'];
}]);

View File

@ -0,0 +1,11 @@
'use strict';
angular.module('adagios.table.cell_last_check', ['adagios.table'])
.controller('CellLastCheckCtrl', ['$scope', function ($scope) {
angular.noop();
}])
.run(['tableConfig', function (tableConfig) {
tableConfig.cellToFieldsMap.last_check = ['last_check'];
}]);

View File

@ -0,0 +1,11 @@
'use strict';
angular.module('adagios.table.cell_service_check', ['adagios.table'])
.controller('CellServiceCheckCtrl', ['$scope', function ($scope) {
angular.noop();
}])
.run(['tableConfig', function (tableConfig) {
tableConfig.cellToFieldsMap.service_check = ['state', 'description', 'plugin_output'];
}]);

View File

@ -0,0 +1,73 @@
'use strict';
angular.module('adagios.table', ['adagios.live',
'adagios.table.cell_host',
'adagios.table.cell_duration',
'adagios.table.cell_service_check',
'adagios.table.cell_last_check',
'adagios.table.cell_hosts_host',
'adagios.table.cell_host_address',
'adagios.table.cell_host_status'
])
.value('tableConfig', { cells: [],
apiName: '',
filters: {},
cellToFieldsMap: {} })
.controller('TableCtrl', ['$scope', 'getServices', 'readConfig', 'tableConfig', function ($scope, getServices, readConfig, tableConfig) {
var requestFields = [],
filters = JSON.parse(tableConfig.filters);
$scope.cells = tableConfig.cells;
angular.forEach($scope.cells, function (key, value) {
angular.forEach(tableConfig.cellToFieldsMap[key], function (_value) {
requestFields.push(_value);
});
});
getServices(requestFields, filters, tableConfig.apiName)
.success(function (data) {
$scope.entries = data;
});
}])
.directive('adgTable', ['tableConfig', function (tableConfig) {
return {
restrict: 'E',
link: function (scope, element, attrs) {
scope.generateTable = function () {
if (!!attrs.cells && !!attrs.apiName) {
tableConfig.cells = attrs.cells.split(',');
tableConfig.apiName = attrs.apiName;
if (!!attrs.filters) {
tableConfig.filters = attrs.filters;
}
return 'components/table/table.html';
}
console.log('<adg-table> "cells" and "api-name" attributes must be defined');
};
},
template: '<div ng-include="generateTable()"></div>'
};
}])
.directive('adgCell', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
scope.getTemplateUrl = function () {
if (!!attrs.type) {
return 'components/table/cell_' + attrs.type + '/cell_' + attrs.type + '.html';
}
console.error('<adg-cell> "type" attribute is undefined');
};
},
template: '<div ng-include="getTemplateUrl()"></div>'
};
});

View File

@ -21,7 +21,7 @@ describe('In Table module', function () {
angular.forEach(cells, function (cell) {
var elem = angular.element('<adg-cell type="' + cell + '"></adg-cell>');
$compile(elem)($rootScope);
$httpBackend.expectGET('table/cell_' + cell + '/cell_' + cell + '.html').respond('');
$httpBackend.expectGET('components/table/cell_' + cell + '/cell_' + cell + '.html').respond('');
$httpBackend.flush();
});
});
@ -30,9 +30,9 @@ describe('In Table module', function () {
describe('adgTable directive', function () {
it('should request table/table.html template', function () {
var elem = angular.element('<adg-table></adg-table>');
var elem = angular.element('<adg-table cells="host,service_check,duration,last_check" api-name="services"></adg-table>');
$compile(elem)($rootScope);
$httpBackend.expectGET('table/table.html').respond('');
$httpBackend.expectGET('components/table/table.html').respond('');
$httpBackend.flush();
});
});

View File

@ -10,6 +10,6 @@ angular.module('adagios.tactical.current_health', ['ngRoute', 'ngJustGage' ])
.directive('adgCurrentHealth', function () {
return {
restrict: 'E',
templateUrl: "tactical/current_health/current_health.html"
templateUrl: 'components/tactical/current_health/current_health.html'
};
});

View File

@ -14,7 +14,7 @@ describe('Current Health tactical submodule', function () {
$controller = _$controller_;
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('tactical/current_health/current_health.html')
$httpBackend.expectGET('components/tactical/current_health/current_health.html')
.respond('<th>Current Health</th>');
}));

View File

@ -17,6 +17,6 @@ angular.module('adagios.tactical.status_overview', ['ngRoute' ])
.directive('adgStatusOverview', function () {
return {
restrict: 'E',
templateUrl: "tactical/status_overview/status_overview.html"
templateUrl: 'components/tactical/status_overview/status_overview.html'
};
});

View File

@ -14,7 +14,7 @@ describe('Status Overview tactical submodule', function () {
$controller = _$controller_;
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('tactical/status_overview/status_overview.html')
$httpBackend.expectGET('components/tactical/status_overview/status_overview.html')
.respond('<td>{{ problems }}</td>');
}));

View File

@ -1,6 +1,5 @@
<div ng-app="adagios.tactical" ng-controller="TacticalCtrl" id="tactical" class="">
<h2>Tactical Overview</h2>
<div id="summary" class="jumbotron">
@ -19,6 +18,4 @@
</div>
<adg-table></adg-table>
</div>

View File

@ -1,19 +1,11 @@
'use strict';
angular.module('adagios.tactical', ['ngRoute',
'adagios.tactical.status_overview',
angular.module('adagios.tactical', ['adagios.tactical.status_overview',
'adagios.tactical.current_health',
'adagios.tactical.top_alert_producers',
'adagios.table'
])
.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/tactical', {
templateUrl: 'tactical/tactical.html',
controller: 'TacticalCtrl'
});
}])
.controller('TacticalCtrl', ['$scope', '$http', function ($scope, $http) {
return;
}]);

View File

@ -21,6 +21,6 @@ angular.module('adagios.tactical.top_alert_producers', ['ngRoute' ])
.directive('adgTopAlertProducers', function () {
return {
restrict: 'E',
templateUrl: "tactical/top_alert_producers/top_alert_producers.html"
templateUrl: 'components/tactical/top_alert_producers/top_alert_producers.html'
};
});

View File

@ -14,7 +14,7 @@ describe('Top Alert Producer tactical submodule', function () {
$controller = _$controller_;
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('tactical/top_alert_producers/top_alert_producers.html')
$httpBackend.expectGET('components/tactical/top_alert_producers/top_alert_producers.html')
.respond('<td>{{ problems }}</td>');
}));

View File

@ -9,6 +9,6 @@ angular.module('adagios.topbar', ['adagios.live'])
.directive('adgTopbar', function () {
return {
restrict: 'E',
templateUrl: "topbar/topbar.html"
templateUrl: 'components/topbar/topbar.html'
};
});

View File

@ -14,7 +14,7 @@ describe('Topbar module', function () {
$controller = _$controller_;
$httpBackend = _$httpBackend_;
$httpBackend.expectGET('topbar/topbar.html').respond('<a>{{ notifications }}</a>');
$httpBackend.expectGET('components/topbar/topbar.html').respond('<a>{{ notifications }}</a>');
}));
describe('TopBarCtrl', function () {

View File

@ -0,0 +1,23 @@
<div ng-app="adagios.tactical" ng-controller="DashboardCtrl" id="tactical" class="">
<h2>Tactical Overview</h2>
<div id="summary" class="jumbotron">
<div class="row">
<div class="col-md-4">
<adg-status-overview></adg-status-overview>
</div>
<div class="col-md-4">
<adg-current-health></adg-current-health>
</div>
<div class="col-md-4">
<adg-top-alert-producers></adg-top-alert-producers>
</div>
</div>
</div>
<adg-table cells="{{dashboardCells}}" api-name="{{dashboardApiName}}" filters="{{dashboardFilters}}"></adg-table>
</div>

View File

@ -0,0 +1,29 @@
'use strict';
angular.module('adagios.tactical', ['ngRoute',
'adagios.tactical.status_overview',
'adagios.tactical.current_health',
'adagios.tactical.top_alert_producers',
'adagios.table'
])
.value('dashboardConfig', {})
.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/dashboard', {
templateUrl: 'dashboard/dashboard.html',
controller: 'DashboardCtrl'
});
}])
.controller('DashboardCtrl', ['$scope', 'dashboardConfig', function ($scope, dashboardConfig) {
$scope.dashboardCells = dashboardConfig.cells.join();
$scope.dashboardApiName = dashboardConfig.apiName;
$scope.dashboardFilters = dashboardConfig.filters;
}])
.run(['readConfig', 'dashboardConfig', function (readConfig, dashboardConfig) {
dashboardConfig.cells = readConfig.dashboardConfig.cells;
dashboardConfig.apiName = readConfig.dashboardConfig.apiName;
dashboardConfig.filters = readConfig.dashboardConfig.filters;
}]);

7
app/hosts/hosts.html Normal file
View File

@ -0,0 +1,7 @@
<div ng-controller="HostsCtrl" id="tactical" class="">
<h2>Hosts</h2>
<adg-table cells="{{hostsCells}}" api-name="{{hostsApiName}}" filters="{{hostsFilters}}"></adg-table>
</div>

26
app/hosts/hosts.js Normal file
View File

@ -0,0 +1,26 @@
'use strict';
angular.module('adagios.view.hosts', ['ngRoute',
'adagios.table'
])
.value('hostsConfig', {})
.config(['$routeProvider', function ($routeProvider) {
$routeProvider.when('/hosts', {
templateUrl: 'hosts/hosts.html',
controller: 'HostsCtrl'
});
}])
.controller('HostsCtrl', ['$scope', 'hostsConfig', function ($scope, hostsConfig) {
$scope.hostsCells = hostsConfig.cells.join();
$scope.hostsApiName = hostsConfig.apiName;
$scope.hostsFilters = hostsConfig.filters;
}])
.run(['readConfig', 'hostsConfig', function (readConfig, hostsConfig) {
hostsConfig.cells = readConfig.hostsConfig.cells;
hostsConfig.apiName = readConfig.hostsConfig.apiName;
hostsConfig.filters = readConfig.hostsConfig.filters;
}]);

View File

@ -2,7 +2,7 @@
<!--[if IE 7]> <html lang="en" ng-app="adagios" class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if lt IE 7]> <html lang="en" ng-app="adagios" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> <!--[if IE 7]> <html lang="en" ng-app="adagios" class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html lang="en" ng-app="adagios" class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html lang="en" ng-app="adagios" class="no-js"> <!--<![endif]-->
<!--[if gt IE 8]><!--> <html lang="en" class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@ -10,6 +10,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="assets/css/app.css">
<meta name="description" content="">
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<!-- Angular -->
<script src="bower_components/angular/angular.js"></script>
@ -17,6 +19,7 @@
<!-- Application -->
<script src="app.js"></script>
<script src="components/config/config.js"></script>
<!-- COMPONENTS -->
<script src="components/live/live.js"></script>
@ -27,19 +30,30 @@
<script src="components/filters/filters.js"></script>
<!-- MODULES -->
<script src="sidebar/sidebar.js"></script>
<script src="components/sidebar/sidebar.js"></script>
<script src="topbar/topbar.js"></script>
<script src="components/topbar/topbar.js"></script>
<script src="tactical/tactical.js"></script>
<script src="tactical/status_overview/status_overview.js"></script>
<script src="tactical/current_health/current_health.js"></script>
<script src="tactical/top_alert_producers/top_alert_producers.js"></script>
<script src="components/tactical/tactical.js"></script>
<script src="components/tactical/status_overview/status_overview.js"></script>
<script src="components/tactical/current_health/current_health.js"></script>
<script src="components/tactical/top_alert_producers/top_alert_producers.js"></script>
<script src="table/table.js"></script>
<script src="components/table/table.js"></script>
<script src="components/table/cell_duration/cell_duration.js"></script>
<script src="components/table/cell_host/cell_host.js"></script>
<script src="components/table/cell_last_check/cell_last_check.js"></script>
<script src="components/table/cell_service_check/cell_service_check.js"></script>
<script src="components/table/cell_hosts_host/cell_hosts_host.js"></script>
<script src="components/table/cell_host_address/cell_host_address.js"></script>
<script src="components/table/cell_host_status/cell_host_status.js"></script>
<script src="bower_components/html5-boilerplate/js/vendor/modernizr-2.6.2.min.js"></script>
<script src="bower_components/moment/moment.js"></script>
<!-- VIEWS -->
<script src="dashboard/dashboard.js"></script>
<script src="hosts/hosts.js"></script>
</head>
<body class="layout color-scheme--dark">
@ -60,7 +74,6 @@
<footer class="footer layout__row" role="contentinfo">...</footer>
</div>
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<script src="bower_components/raphael/raphael-min.js"></script>
<script src="bower_components/justgage-toorshia/justgage.js"></script>
<script src="bower_components/bootstrap-sass-official/assets/javascripts/bootstrap.js"></script>

View File

@ -1,54 +0,0 @@
'use strict';
angular.module('adagios.table', ['ngRoute',
'adagios.live'
])
.controller('TableCtrl', ['$scope', 'getServices', function ($scope, getServices) {
var requestFields = [],
filters = {};
$scope.cells = ['host', 'service_check', 'duration', 'last_check'];
// The module directory name must be cell_ + key
$scope.cellToFieldsMap = {
host: [ 'host_state', 'host_name' ],
service_check: ['state', 'description', 'plugin_output'],
duration: ['last_state_change'],
last_check: ['last_check']
};
angular.forEach($scope.cells, function (key, value) {
angular.forEach($scope.cellToFieldsMap[key], function (_value) {
requestFields.push(_value);
});
});
getServices(requestFields, filters)
.success(function (data) {
$scope.entries = data;
});
}])
.directive('adgTable', function () {
return {
restrict: 'E',
templateUrl: 'table/table.html'
};
})
.directive('adgCell', function () {
return {
restrict: 'E',
link: function (scope, element, attrs) {
scope.getTemplateUrl = function () {
if (attrs.type) {
return 'table/cell_' + attrs.type + '/cell_' + attrs.type + '.html';
}
console.error('<adg-cell> "type" attribute is undefined');
};
},
template: '<div ng-include="getTemplateUrl()"></div>'
};
});