report UI

Change-Id: Iccb042fb542d8dea2b1fe2826bc0bfbac77d83a7
This commit is contained in:
sharonlucong 2015-01-15 13:55:07 -08:00
parent 0d41c806be
commit 6f593f1fa0
8 changed files with 6829 additions and 1670 deletions

View File

@ -1056,3 +1056,13 @@ h4.widget-title:hover {
.loadingMask .mask{
opacity: 0.5;
}
.centerLoading{
padding-top: 20%;
padding-left: 45%;
}
.popover-title{
background: #F2DEDE;
}
.yellow{
color: #FEE188 !important;
}

View File

@ -18,7 +18,7 @@ define([
var compassModule = ng.module('app', [
'compass.login',
'compass.services',
// 'compassAppDev',
// 'compassAppDev',
'compass.clusterlist',
'compass.cluster',
'compass.wizard',

File diff suppressed because one or more lines are too long

View File

@ -84,6 +84,13 @@
</a>
</li>
<li ng-class="{active:state.includes('cluster.report')}">
<a ui-sref="cluster.report">
<i class="menu-icon glyphicon glyphicon-list-alt glyphicon-list-alt"></i>
<span class="menu-text">Report</span>
</a>
</li>
</ul>
<div class="sidebar-toggle sidebar-collapse" ng-click="sidebarCollapse = !sidebarCollapse">

View File

@ -82,6 +82,10 @@
</div>
<div class="pull-right">
<div class="btn-group" dropdown>
<button type="button" class="btn btn-info" ng-click="startChecking()" ng-disabled="clusterProgress.state == 'INSTALLING'">
Report
</button>
<button type="button" class="btn btn-info dropdown-toggle" ng-disabled="clusterProgress.state == 'INSTALLING'">
Actions
<span class="ace-icon fa fa-caret-down icon-on-right"></span>

View File

@ -0,0 +1,139 @@
<div ng-if="!showData && !isTimeout" class="centerLoading">
<i class='class="ace-icon fa fa-spinner fa-spin bigger-300 orange'></i>
<span>loading...</span>
</div>
<div ng-if="isTimeout" class="centerLoading">
<i class='class="ce-icon fa fa-times bigger-300 red'></i>
<span>Timeout Error</span>
</div>
<div ng-if="showData && !isTimeout" class="widget-box transparent" style="border-radius: 7px;" ng-repeat="(categoryName, categoryValue) in categories">
<div class="widget-header">
<h4 class="widget-title">{{categoryName}}</h4>
</div>
<div class="widget-body">
<div class="widget-main">
<div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true">
<span ng-if="showData && !isTimeout">
<div class="panel panel-default" ng-repeat = "report in reports | FilterByCategory: categoryName">
<div class="panel-heading" role="tab" id="headingOne">
<h4 class="panel-title">
<span>{{report.name}}</span>
<span ng-if="reportStates[report.name] =='success'">
<i class='class="ace-icon fa fa fa-check bigger-160 green'></i>
</span>
<span ng-if="reportStates[report.name] =='finished'">
<i class='class="ace-icon fa fa-exclamation bigger-160 yellow'></i>
</span>
<span ng-if="reportStates[report.name] =='verifying'">
<i class='class="ace-icon fa fa-spinner fa-spin bigger-160 orange'></i>
</span>
<span ng-if="reportStates[report.name] =='error'">
<i class='class="ace-icon fa fa-times bigger-160 red'></i>
</span>
<button class="pull-right btn btn-default btn-xs" data-toggle="collapse" data-parent="#accordion" href="#{{report.name}}" aria-expanded="true" aria-controls="{{report.name}}" ng-disabled="reportStates[report.name] == 'verifying'" ng-style="{color: notFinished ? 'white' : 'grey'}">
<i class="glyphicon glyphicon-chevron-down"></i>
</button>
</h4>
</div>
<div id="{{report.name}}" class="panel-collapse collapse" role="tabpanel" aria-labelledby="headingOne">
<div class="panel-body">
<table class="table" style="font-size:13px">
<thead>
<tr class="info">
<th>Actions</th>
<th>Avg(sec)</th>
<th>Max(sec)</th>
<th>Min(sec)</th>
<th>Errors</th>
<th>Success</th>
<th>Total</th>
</tr>
</thead>
<tr ng-repeat="(key,detail) in details[report.name]">
<td>{{key}}</td>
<td>{{detail.duration.summary["avg (sec)"]}}</td>
<td>{{detail.duration.summary["max (sec)"]}}</td>
<td>{{detail.duration.summary["min (sec)"]}}</td>
<td>
<span ng-if="detail.duration.summary.errors.count == 0">{{detail.duration.summary.errors.count}}</span>
<span ng-if="detail.duration.summary.errors.count!= 0">
<button id="popover" data-trigger="hover" style = "border-radius:20px!important" class="btn btn-xs btn-danger popover-hide"
title='{{detail.duration.summary.errors.details[0][0]}}'
type="button"
data-toggle="modal"
data-placement="right"
data-target="#{{createModalId(key,report.name)}}"
data-content='{{detail.duration.summary.errors.details[0][1]}}'>
{{detail.duration.summary.errors.count}}
</button>
<!-- Modal -->
<div class="modal fade" id="{{createModalId(key,report.name)}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header" style="background:#B74635">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="myModalLabel">Error Details</h4>
</div>
<div class="modal-body">
<table class="table">
<tr>
<td><strong>Exception Type</strong>
</td>
<td>{{detail.duration.summary.errors.details[0][0]}}</td>
</tr>
<tr>
<td><strong>Exception Message</strong>
</td>
<td>{{detail.duration.summary.errors.details[0][1]}}</td>
</tr>
<tr>
<td></td>
<td>
<p ng-bind-html="detail.duration.summary.errors.details[0][2] | nl2br"></p>
</td>
</tr>
</table>
</div>
<div class="modal-footer" style="background:#F2DEDE">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script>
$(function() {
$('.popover-show').popover('show');
});
$(function() {
$('.popover-hide').popover('hide');
});
$(function() {
$('.popover-destroy').popover('destroy');
});
$(function() {
$('.popover-toggle').popover('toggle');
});
$(function() {
$(".popover-options a").popover({
html: true
});
});
$("#popover").popover({
trigger: "hover"
});
</script>
</span>
</td>
<td>{{detail.duration.summary["success"]}}</td>
<td>{{detail.duration.summary["total"]}}</td>
</tr>
</table>
</div>
</div>
</div>
</span>
</div>
</div>
</div>
</div>

View File

@ -62,8 +62,125 @@ define(['angular'], function() {
controller: "clusterLogCtrl",
templateUrl: 'src/app/cluster/cluster-log.tpl.html',
authenticate: true
})
.state('cluster.report', {
url: '/report',
controller: "clusterReportCtrl",
templateUrl: 'src/app/cluster/cluster-report.tpl.html',
authenticate: true
});
});
clusterModule.controller('clusterReportCtrl', function($scope, $state, dataService, $stateParams, $timeout, $modal) {
$scope.details = {};
$scope.modalId = {};
$scope.errorActions = {};
$scope.promise = $timeout(timeoutAlert, 1200000);
var progressTimer;
var fireTimer = true;
$scope.notFinished = true;
$scope.reportStates = {};
var clusterId = $stateParams.id;
$scope.showData = false;
$scope.showDetails = false;
$scope.isTimeout = false;
$scope.categories = {};
$scope.dtLength = 0;
function timeoutAlert() {
$scope.isTimeout = true;
}
function isEmpty(obj) {
for (var prop in obj) {
if (obj.hasOwnProperty(prop))
return false;
}
return true;
}
var getAllReports = function() {
if (!$scope.isTimeout) {
dataService.getHealthReports(clusterId).success(function(data) {
if (!isEmpty(data)) {
if (data.length != $scope.dtLength) {
$scope.dtLength = data.length;
$scope.reportsData = $timeout(getAllReports, 3000);
} else {
$scope.reports = data;
$scope.showData = true;
$timeout.cancel($scope.promise);
angular.forEach(data, function(dt) {
if (!isEmpty($scope.categories) && !isEmpty($scope.categories[dt.category])) {
$scope.categories[dt.category].push(dt.name);
} else {
$scope.categories[dt.category] = [];
$scope.categories[dt.category].push(dt.name);
}
});
var getClusterReport = function() {
angular.forEach($scope.reports, function(rd) {
if (($scope.reportStates[rd.name] != "finished" && $scope.reportStates[rd.name] != "error" && $scope.reportStates[rd.name] != "success") || isEmpty($scope.reportStates[rd.name])) {
var getResults = function() {
dataService.getIndividualReports(rd.cluster_id, rd.name).success(function(dt) {
if (!isEmpty(dt.report)) {
$scope.details[rd.name] = dt.report.results.actions;
for (var i in dt.report.results.actions) {
var str = i + rd.name;
$scope.modalId[i + rd.name] = str.replace(".", "-");
$scope.createModalId = function(action, name) {
return $scope.modalId[action + name];
};
}
$scope.reportStates[rd.name] = dt.state;
} else {
$scope.reportStates[rd.name] = dt.state;
$scope.showDetails = false;
$timeout(getResults, 2000);
}
});
}
getResults();
}
});
if (fireTimer) {
progressTimer = $timeout(getClusterReport, 3000);
};
}
getClusterReport();
$scope.$on('$destroy', function() {
fireTimer = false;
$timeout.cancel(progressTimer);
});
}
} else {
$timeout(getAllReports, 2000);
$scope.showData = false;
}
});
}
}
getAllReports();
});
clusterModule.filter('FilterByCategory', function() {
return function(items, categoryName) {
var filtered = [];
for (var i = 0; i < items.length; i++) {
var item = items[i];
if (item.category == categoryName) {
filtered.push(item);
}
}
return filtered;
}
});
clusterModule.filter('nl2br', function($sce) {
return function(text) {
return text ? $sce.trustAsHtml(text.replace(/\n/g, '<br/>')) : '';
};
});
clusterModule.controller('clusterCtrl', function($scope, $state, dataService, $stateParams) {
$scope.clusterId = $stateParams.id;
@ -72,7 +189,6 @@ define(['angular'], function() {
dataService.getClusterById($scope.clusterId).success(function(data) {
$scope.clusterInfo = data;
});
});
clusterModule.directive('clusternav', function($timeout) {
return {
@ -98,11 +214,20 @@ define(['angular'], function() {
});
clusterModule.controller('clusterProgressCtrl', function($scope, dataService, $stateParams, $filter, ngTableParams, $timeout, $modal, clusterhostsData) {
clusterModule.controller('clusterProgressCtrl', function($scope, dataService, $state, $stateParams, $filter, ngTableParams, $timeout, $modal, clusterhostsData, $rootScope) {
var clusterId = $stateParams.id;
var progressTimer;
var fireTimer = true;
$scope.hosts = clusterhostsData;
var request = {
"check_health": null
}
$scope.startChecking = function() {
dataService.startHealthCheck($scope.clusterId, request).success(function(data) {
$state.go('cluster.report', data);
});
};
var getClusterProgress = function() {
dataService.getClusterProgress(clusterId).success(function(data) {

View File

@ -126,6 +126,23 @@ define(['angular','uiBootstrap'], function(ng, uiBootstrap) {
this.getUserLog = function() {
return $http.get(settings.apiUrlBase + '/users/logs');
}
this.getHealthReports = function(id){
return $http.get(settings.apiUrlBase + '/clusters/' + id + '/healthreports');
};
this.getIndividualReports = function(id, name){
return $http.get(settings.apiUrlBase + '/clusters/' + id + '/healthreports/' + name);
};
this.postHealthCheck = function(id, checkHealth){
return $http.post(settings.apiUrlBase + '/clusters/' + id + '/action', angular.toJason(checkHealth));
};
this.startHealthCheck = function(id, request){
return $http.post(settings.apiUrlBase + '/clusters/' + id + '/action',angular.toJson(request));
};
this.getClusters = function() {
return $http.get(settings.apiUrlBase + '/clusters');
};