mirror of
https://github.com/ansible/awx.git
synced 2026-01-09 23:12:08 -03:30
Dashboard refresh
This commit is contained in:
parent
f4e3126c43
commit
12af62f671
@ -210,4 +210,3 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -29,11 +29,7 @@ import {Authenticate} from 'tower/controllers/Authentication';
|
|||||||
import {CredentialsAdd, CredentialsEdit, CredentialsList} from 'tower/controllers/Credentials';
|
import {CredentialsAdd, CredentialsEdit, CredentialsList} from 'tower/controllers/Credentials';
|
||||||
import {JobsListController} from 'tower/controllers/Jobs';
|
import {JobsListController} from 'tower/controllers/Jobs';
|
||||||
import {PortalController} from 'tower/controllers/Portal';
|
import {PortalController} from 'tower/controllers/Portal';
|
||||||
|
|
||||||
import dataServices from 'tower/services/_data-services';
|
|
||||||
import dashboardGraphs from 'tower/directives/_dashboard-graphs';
|
|
||||||
import systemTracking from 'tower/system-tracking/main';
|
import systemTracking from 'tower/system-tracking/main';
|
||||||
|
|
||||||
import routeExtensions from 'tower/shared/route-extensions/main';
|
import routeExtensions from 'tower/shared/route-extensions/main';
|
||||||
import breadcrumbs from 'tower/shared/breadcrumbs/main';
|
import breadcrumbs from 'tower/shared/breadcrumbs/main';
|
||||||
|
|
||||||
@ -41,6 +37,7 @@ import breadcrumbs from 'tower/shared/breadcrumbs/main';
|
|||||||
import setupMenu from 'tower/setup-menu/main';
|
import setupMenu from 'tower/setup-menu/main';
|
||||||
import mainMenu from 'tower/main-menu/main';
|
import mainMenu from 'tower/main-menu/main';
|
||||||
import browserData from 'tower/browser-data/main';
|
import browserData from 'tower/browser-data/main';
|
||||||
|
import dashboard from 'tower/dashboard/main';
|
||||||
|
|
||||||
import {JobDetailController} from 'tower/controllers/JobDetail';
|
import {JobDetailController} from 'tower/controllers/JobDetail';
|
||||||
import {JobStdoutController} from 'tower/controllers/JobStdout';
|
import {JobStdoutController} from 'tower/controllers/JobStdout';
|
||||||
@ -79,14 +76,13 @@ var tower = angular.module('Tower', [
|
|||||||
'ngSanitize',
|
'ngSanitize',
|
||||||
'ngCookies',
|
'ngCookies',
|
||||||
'RestServices',
|
'RestServices',
|
||||||
dataServices.name,
|
|
||||||
dashboardGraphs.name,
|
|
||||||
routeExtensions.name,
|
routeExtensions.name,
|
||||||
browserData.name,
|
browserData.name,
|
||||||
breadcrumbs.name,
|
breadcrumbs.name,
|
||||||
systemTracking.name,
|
systemTracking.name,
|
||||||
setupMenu.name,
|
setupMenu.name,
|
||||||
mainMenu.name,
|
mainMenu.name,
|
||||||
|
dashboard.name,
|
||||||
'AuthService',
|
'AuthService',
|
||||||
'Utilities',
|
'Utilities',
|
||||||
'LicenseHelper',
|
'LicenseHelper',
|
||||||
@ -149,8 +145,6 @@ var tower = angular.module('Tower', [
|
|||||||
'AccessHelper',
|
'AccessHelper',
|
||||||
'SelectionHelper',
|
'SelectionHelper',
|
||||||
'HostGroupsFormDefinition',
|
'HostGroupsFormDefinition',
|
||||||
'DashboardCountsWidget',
|
|
||||||
'DashboardJobsWidget',
|
|
||||||
'PortalJobsWidget',
|
'PortalJobsWidget',
|
||||||
'StreamWidget',
|
'StreamWidget',
|
||||||
'JobsHelper',
|
'JobsHelper',
|
||||||
@ -863,10 +857,9 @@ var tower = angular.module('Tower', [
|
|||||||
templateUrl: urlPrefix + 'partials/home.html',
|
templateUrl: urlPrefix + 'partials/home.html',
|
||||||
controller: Home,
|
controller: Home,
|
||||||
resolve: {
|
resolve: {
|
||||||
graphData: ['$q', 'jobStatusGraphData', 'hostCountGraphData', 'FeaturesService', function($q, jobStatusGraphData, hostCountGraphData, FeaturesService) {
|
graphData: ['$q', 'jobStatusGraphData', 'FeaturesService', function($q, jobStatusGraphData, FeaturesService) {
|
||||||
return $q.all({
|
return $q.all({
|
||||||
jobStatus: jobStatusGraphData.get("month", "all"),
|
jobStatus: jobStatusGraphData.get("month", "all"),
|
||||||
hostCounts: hostCountGraphData.get(),
|
|
||||||
features: FeaturesService.get()
|
features: FeaturesService.get()
|
||||||
});
|
});
|
||||||
}]
|
}]
|
||||||
|
|||||||
@ -26,41 +26,31 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function Home($scope, $compile, $routeParams, $rootScope, $location, $log, Wait, DashboardCounts, DashboardJobs,
|
export function Home($scope, $compile, $routeParams, $rootScope, $location, $log, Wait,
|
||||||
ClearScope, Stream, Rest, GetBasePath, ProcessErrors, $window, graphData){
|
ClearScope, Stream, Rest, GetBasePath, ProcessErrors, $window, graphData){
|
||||||
|
|
||||||
ClearScope('home');
|
ClearScope('home');
|
||||||
|
|
||||||
var borderStyles;
|
var dataCount = 0;
|
||||||
|
|
||||||
if (!$routeParams.login) {
|
if ($scope.removeDashboardDataLoadComplete) {
|
||||||
// If we're not logging in, start the Wait widget. Otherwise, it's already running.
|
$scope.removeDashboardDataLoadComplete();
|
||||||
//Wait('start');
|
|
||||||
}
|
}
|
||||||
|
$scope.removeDashboardDataLoadComplete = $scope.$on('dashboardDataLoadComplete', function () {
|
||||||
|
dataCount++;
|
||||||
|
if (dataCount === 3) {
|
||||||
|
Wait("stop");
|
||||||
|
dataCount = 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if ($scope.removeDashboardReady) {
|
if ($scope.removeDashboardReady) {
|
||||||
$scope.removeDashboardReady();
|
$scope.removeDashboardReady();
|
||||||
}
|
}
|
||||||
$scope.removeDashboardReady = $scope.$on('dashboardReady', function (e, data) {
|
$scope.removeDashboardReady = $scope.$on('dashboardReady', function (e, data) {
|
||||||
|
$scope.dashboardCountsData = data;
|
||||||
nv.dev=false;
|
|
||||||
|
|
||||||
|
|
||||||
borderStyles = {"border": "1px solid #A9A9A9",
|
|
||||||
"border-radius": "4px",
|
|
||||||
"padding": "5px",
|
|
||||||
"margin-bottom": "15px"};
|
|
||||||
$('.graph-container').css(borderStyles);
|
|
||||||
|
|
||||||
DashboardCounts({
|
|
||||||
scope: $scope,
|
|
||||||
target: 'dash-counts',
|
|
||||||
dashboard: data
|
|
||||||
});
|
|
||||||
|
|
||||||
// // chart.update();
|
|
||||||
|
|
||||||
$scope.graphData = graphData;
|
$scope.graphData = graphData;
|
||||||
|
$scope.$emit('dashboardDataLoadComplete');
|
||||||
|
|
||||||
var cleanupJobListener =
|
var cleanupJobListener =
|
||||||
$rootScope.$on('DataReceived:JobStatusGraph', function(e, data) {
|
$rootScope.$on('DataReceived:JobStatusGraph', function(e, data) {
|
||||||
@ -70,16 +60,25 @@ export function Home($scope, $compile, $routeParams, $rootScope, $location, $log
|
|||||||
$scope.$on('$destroy', function() {
|
$scope.$on('$destroy', function() {
|
||||||
cleanupJobListener();
|
cleanupJobListener();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
DashboardJobs({
|
|
||||||
scope: $scope,
|
|
||||||
target: 'dash-jobs-list',
|
|
||||||
dashboard: data
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if ($scope.removeDashboardJobsListReady) {
|
||||||
|
$scope.removeDashboardJobsListReady();
|
||||||
|
}
|
||||||
|
$scope.removeDashboardJobsListReady = $scope.$on('dashboardJobsListReady', function (e, data) {
|
||||||
|
$scope.dashboardJobsListData = data;
|
||||||
|
$scope.$emit('dashboardDataLoadComplete');
|
||||||
|
});
|
||||||
|
|
||||||
|
if ($scope.removeDashboardJobTemplatesListReady) {
|
||||||
|
$scope.removeDashboardJobTemplatesListReady();
|
||||||
|
}
|
||||||
|
$scope.removeDashboardJobTemplatesListReady = $scope.$on('dashboardJobTemplatesListReady', function (e, data) {
|
||||||
|
$scope.dashboardJobTemplatesListData = data;
|
||||||
|
$scope.$emit('dashboardDataLoadComplete');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
$scope.showActivity = function () {
|
$scope.showActivity = function () {
|
||||||
Stream({
|
Stream({
|
||||||
scope: $scope
|
scope: $scope
|
||||||
@ -97,13 +96,30 @@ export function Home($scope, $compile, $routeParams, $rootScope, $location, $log
|
|||||||
.error(function (data, status) {
|
.error(function (data, status) {
|
||||||
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard: ' + status });
|
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard: ' + status });
|
||||||
});
|
});
|
||||||
|
Rest.setUrl(GetBasePath("jobs") + "?order_by=-finished&page_size=5&finished__isnull=false");
|
||||||
|
Rest.get()
|
||||||
|
.success(function (data) {
|
||||||
|
data = data.results;
|
||||||
|
$scope.$emit('dashboardJobsListReady', data);
|
||||||
|
})
|
||||||
|
.error(function (data, status) {
|
||||||
|
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard jobs list: ' + status });
|
||||||
|
});
|
||||||
|
Rest.setUrl(GetBasePath("job_templates") + "?order_by=-last_job_run&page_size=5&last_job_run__isnull=false");
|
||||||
|
Rest.get()
|
||||||
|
.success(function (data) {
|
||||||
|
data = data.results;
|
||||||
|
$scope.$emit('dashboardJobTemplatesListReady', data);
|
||||||
|
})
|
||||||
|
.error(function (data, status) {
|
||||||
|
ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get dashboard job templates list: ' + status });
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.refresh();
|
$scope.refresh();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Home.$inject = ['$scope', '$compile', '$routeParams', '$rootScope', '$location', '$log','Wait', 'DashboardCounts', 'DashboardJobs',
|
Home.$inject = ['$scope', '$compile', '$routeParams', '$rootScope', '$location', '$log','Wait',
|
||||||
'ClearScope', 'Stream', 'Rest', 'GetBasePath', 'ProcessErrors', '$window', 'graphData'
|
'ClearScope', 'Stream', 'Rest', 'GetBasePath', 'ProcessErrors', '$window', 'graphData'
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,70 @@
|
|||||||
|
/** @define DashboardCounts */
|
||||||
|
|
||||||
|
.DashboardCounts {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: stretch;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
padding-top: 0;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardCounts-buttonStyle {
|
||||||
|
text-align: center;
|
||||||
|
padding: 8px;
|
||||||
|
padding-bottom: 11px;
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 710px) {
|
||||||
|
.DashboardCounts {
|
||||||
|
margin-bottom: -15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardCounts-buttonStyle {
|
||||||
|
border: 1px solid #aaa;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
width: 33%;
|
||||||
|
flex-basis: ~"calc(33% - 7px)";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardCounts-buttonStyle:hover {
|
||||||
|
background-color: #1778c3;
|
||||||
|
border-color: #1778c3;
|
||||||
|
|
||||||
|
.DashboardCounts-number,
|
||||||
|
.DashboardCounts-label {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardCounts-buttonStyle.is-failure:hover {
|
||||||
|
background-color: #ff5850;
|
||||||
|
border-color: #ff5850;
|
||||||
|
|
||||||
|
.DashboardCounts-number,
|
||||||
|
.DashboardCounts-label {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardCounts-number {
|
||||||
|
font-size: 30px;
|
||||||
|
line-height: 26px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardCounts-number.is-failure {
|
||||||
|
color: #ff5850;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardCounts-label {
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
/* jshint unused: vars */
|
||||||
|
export default
|
||||||
|
[ '$rootScope',
|
||||||
|
function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: {
|
||||||
|
data: '='
|
||||||
|
},
|
||||||
|
replace: false,
|
||||||
|
templateUrl: '/static/js/dashboard/counts/dashboard-counts.partial.html',
|
||||||
|
link: function(scope, element, attrs) {
|
||||||
|
scope.$watch("data", function(data) {
|
||||||
|
if (data && data.hosts) {
|
||||||
|
createCounts(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function addFailureToCount(val) {
|
||||||
|
if (val.isFailureCount) {
|
||||||
|
// delete isFailureCount
|
||||||
|
if (val.number > 0) {
|
||||||
|
val.isFailure = true;
|
||||||
|
} else {
|
||||||
|
val.isFailure = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val.isFailure = false;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createCounts(data) {
|
||||||
|
scope.counts = _.map([
|
||||||
|
{
|
||||||
|
url: "/#/home/hosts",
|
||||||
|
number: scope.data.hosts.total,
|
||||||
|
label: "Hosts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "/#/home/hosts?has_active_failures=true",
|
||||||
|
number: scope.data.hosts.failed,
|
||||||
|
label: "Failed Hosts",
|
||||||
|
isFailureCount: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "/#/inventories",
|
||||||
|
number: scope.data.inventories.total,
|
||||||
|
label: "Inventories",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "/#/inventories/?inventory_sources_with_failures",
|
||||||
|
number: scope.data.inventories.inventory_failed,
|
||||||
|
label: "Inventory Sync Failures",
|
||||||
|
isFailureCount: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "/#/projects",
|
||||||
|
number: scope.data.projects.total,
|
||||||
|
label: "Projects"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: "/#/projects/?status=failed",
|
||||||
|
number: scope.data.projects.failed,
|
||||||
|
label: "Projects Sync Failures",
|
||||||
|
isFailureCount: true
|
||||||
|
}
|
||||||
|
], function(val) { return addFailureToCount(val); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
@ -0,0 +1,10 @@
|
|||||||
|
<div class="DashboardCounts">
|
||||||
|
<a class="DashboardCounts-buttonStyle" ng-repeat="count in counts" ng-href="{{ count.url }}"
|
||||||
|
ng-class="{'is-failure': {{ count.isFailure }} }">
|
||||||
|
<div class="DashboardCounts-number"
|
||||||
|
ng-class="{'is-failure': {{ count.isFailure }} }">
|
||||||
|
{{ count.number }}
|
||||||
|
</div>
|
||||||
|
<h6 class="DashboardCounts-label" >{{ count.label }}</h6>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
5
awx/ui/static/js/dashboard/counts/main.js
Normal file
5
awx/ui/static/js/dashboard/counts/main.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import dashboardCountsDirective from 'tower/dashboard/counts/dashboard-counts.directive';
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('DashboardCountModules', [])
|
||||||
|
.directive('dashboardCounts', dashboardCountsDirective);
|
||||||
43
awx/ui/static/js/dashboard/dashboard.block.less
Normal file
43
awx/ui/static/js/dashboard/dashboard.block.less
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/** @define Dashboard */
|
||||||
|
|
||||||
|
.Dashboard {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Dashboard-counts {
|
||||||
|
flex: initial;
|
||||||
|
width: 100%;
|
||||||
|
border: 1px solid #a9a9a9;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Dashboard-graphs {
|
||||||
|
flex: initial;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Dashboard-list {
|
||||||
|
display: flex;
|
||||||
|
border: 1px solid #a9a9a9;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 15px;
|
||||||
|
width: 50%;
|
||||||
|
padding: 15px;
|
||||||
|
flex-basis: ~"calc(50% - 7px)";
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 710px) {
|
||||||
|
.Dashboard-counts {
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Dashboard-list {
|
||||||
|
flex: initial;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
awx/ui/static/js/dashboard/dashboard.directive.js
Normal file
13
awx/ui/static/js/dashboard/dashboard.directive.js
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/* jshint unused: vars */
|
||||||
|
export default
|
||||||
|
[ '$rootScope',
|
||||||
|
function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: true,
|
||||||
|
templateUrl: '/static/js/dashboard/dashboard.partial.html',
|
||||||
|
link: function(scope, element, attrs) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
11
awx/ui/static/js/dashboard/dashboard.partial.html
Normal file
11
awx/ui/static/js/dashboard/dashboard.partial.html
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<div class="Dashboard">
|
||||||
|
<dashboard-counts class="Dashboard-counts" data="dashboardData"></dashboard-counts>
|
||||||
|
<dashboard-graphs class="Dashboard-graphs"></dashboard-graphs>
|
||||||
|
<job-templates-list class="Dashboard-list
|
||||||
|
Dashboard-list--jobTemplates"
|
||||||
|
data="dashboardJobTemplatesListData">
|
||||||
|
</job-templates-list>
|
||||||
|
<jobs-list class="Dashboard-list Dashboard-list--jobs"
|
||||||
|
data="dashboardJobsListData">
|
||||||
|
</jobs-list>
|
||||||
|
</div>
|
||||||
101
awx/ui/static/js/dashboard/graphs/dashboard-graphs.block.less
Normal file
101
awx/ui/static/js/dashboard/graphs/dashboard-graphs.block.less
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/** @define DashboardGraphs */
|
||||||
|
|
||||||
|
.DashboardGraphs {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-top: 15px;
|
||||||
|
border: solid 1px #a9a9a9;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-tabSection {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-tab {
|
||||||
|
flex: 1;
|
||||||
|
padding: 10px;
|
||||||
|
border-right: solid 1px #a9a9a9;
|
||||||
|
border-bottom: solid 1px #a9a9a9;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 20px;
|
||||||
|
background-color: #ccc;
|
||||||
|
color: #545454;
|
||||||
|
background-color: #EAEAEA;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-tab--firstTab {
|
||||||
|
border-top-left-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-tab--lastTab {
|
||||||
|
border-top-right-radius: 4px;
|
||||||
|
border-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-tab:hover {
|
||||||
|
color: #000;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-tab.is-selected {
|
||||||
|
background-color: #fff;
|
||||||
|
color: #000;
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-tab.is-selected:hover {
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-graphSection {
|
||||||
|
display: block;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-graphContainer {
|
||||||
|
width: 0%;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-graphContainer.is-selected {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-graph {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 19px;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-graphToolbar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-filterDropdown {
|
||||||
|
flex: initial;
|
||||||
|
font-size: 12px;
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-filterDropdownItems {
|
||||||
|
position: fixed;
|
||||||
|
left: initial;
|
||||||
|
top: initial;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-filterDropdownItems--period {
|
||||||
|
margin-left: -42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardGraphs-filterDropdownItems--jobType {
|
||||||
|
margin-left: -84px;
|
||||||
|
}
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
/* jshint unused: vars */
|
||||||
|
export default
|
||||||
|
[ '$rootScope',
|
||||||
|
function() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
scope: true,
|
||||||
|
templateUrl: '/static/js/dashboard/graphs/dashboard-graphs.partial.html',
|
||||||
|
link: function(scope, element, attrs) {
|
||||||
|
function clearGraphs() {
|
||||||
|
scope.jobStatusSelected = false;
|
||||||
|
scope.hostStatusSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.toggleGraphStatus = function (graphType) {
|
||||||
|
clearGraphs();
|
||||||
|
if (graphType === "jobStatus") {
|
||||||
|
scope.jobStatusSelected = true;
|
||||||
|
} else if (graphType === "hostStatus") {
|
||||||
|
scope.hostStatusSelected = true;
|
||||||
|
}
|
||||||
|
scope.$broadcast("resizeGraphs");
|
||||||
|
};
|
||||||
|
|
||||||
|
// initially toggle jobStatus graph
|
||||||
|
clearGraphs();
|
||||||
|
scope.toggleGraphStatus("jobStatus");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
<div class="DashboardGraphs">
|
||||||
|
<div class="DashboardGraphs-tabSection">
|
||||||
|
<div class="DashboardGraphs-tab DashboardGraphs-tab--firstTab"
|
||||||
|
ng-click="toggleGraphStatus('jobStatus')"
|
||||||
|
ng-class="{'is-selected': jobStatusSelected }">
|
||||||
|
Job Status
|
||||||
|
</div>
|
||||||
|
<div class="DashboardGraphs-tab DashboardGraphs-tab--lastTab"
|
||||||
|
ng-click="toggleGraphStatus('hostStatus')"
|
||||||
|
ng-class="{'is-selected': hostStatusSelected }">
|
||||||
|
Host Status
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="DashboardGraphs-graphSection">
|
||||||
|
<div class="DashboardGraphs-graphContainer" auto-size-module
|
||||||
|
graph-type="jobsStatus"
|
||||||
|
ng-class="{'is-selected': jobStatusSelected }">
|
||||||
|
<job-status-graph class="DashboardGraphs-graph
|
||||||
|
DashboardGraphs-graph--jobStatusGraph"
|
||||||
|
data="graphData.jobStatus" period="month" job-type="all">
|
||||||
|
</job-status-graph>
|
||||||
|
</div>
|
||||||
|
<div class="DashboardGraphs-graphContainer" auto-size-module
|
||||||
|
graph-type="hostStatus"
|
||||||
|
ng-class="{'is-selected': hostStatusSelected }">
|
||||||
|
<host-status-graph class="DashboardGraphs-graph
|
||||||
|
DashboardGraphs-graph--hostStatusGraph"
|
||||||
|
data="dashboardData">
|
||||||
|
</host-status-graph>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@ -53,37 +53,35 @@ export default function() {
|
|||||||
// Calling chartModel.update() at the end instructs nv to process our changes.
|
// Calling chartModel.update() at the end instructs nv to process our changes.
|
||||||
//
|
//
|
||||||
return function adjustGraphSize(chartModel, element) {
|
return function adjustGraphSize(chartModel, element) {
|
||||||
var parentHeight = element.parent().parent().height();
|
if (chartModel) {
|
||||||
var toolbarHeight = element.find('.toolbar').height();
|
var margins = chartModel.margin();
|
||||||
var container = element.find('svg').parent();
|
var graph = d3.select(element.find('svg')[0]);
|
||||||
var margins = chartModel.margin();
|
var width = parseInt(graph.style('width')) - margins.left - margins.right;
|
||||||
|
// var height = parseInt(graph.style('height')) - margins.top - margins.bottom;
|
||||||
|
// console.log(height);
|
||||||
|
var height = 200;
|
||||||
|
|
||||||
var newHeight = parentHeight - toolbarHeight - margins.bottom;
|
chartModel.xRange([0, width]);
|
||||||
|
chartModel.yRange([height, 0]);
|
||||||
|
|
||||||
$(container).height(newHeight);
|
chartModel.xAxis.ticks(Math.max(width / 75, 2));
|
||||||
|
chartModel.yAxis.ticks(Math.max(height / 50, 2));
|
||||||
|
|
||||||
var graph = d3.select(element.find('svg')[0]);
|
if (height < 160) {
|
||||||
var width = parseInt(graph.style('width')) - margins.left - margins.right;
|
graph.select('.y.nv-axis').select('.domain').style('display', 'none');
|
||||||
var height = parseInt(graph.style('height')) - margins.top - margins.bottom;
|
graph.select('.y.nv-axis').select('.domain').style('display', 'initial');
|
||||||
|
}
|
||||||
|
|
||||||
chartModel.xRange([0, width]);
|
graph.select('.x.nv-axis')
|
||||||
chartModel.yRange([height, 0]);
|
.attr('transform', 'translate(0, ' + height + ')')
|
||||||
|
.call(chartModel.xAxis);
|
||||||
|
|
||||||
chartModel.xAxis.ticks(Math.max(width / 75, 2));
|
graph.selectAll('.line')
|
||||||
chartModel.yAxis.ticks(Math.max(height / 50, 2));
|
.attr('d', chartModel.lines);
|
||||||
|
|
||||||
if (height < 160) {
|
if (chartModel.update) {
|
||||||
graph.select('.y.nv-axis').select('.domain').style('display', 'none');
|
chartModel.update();
|
||||||
graph.select('.y.nv-axis').select('.domain').style('display', 'initial');
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
graph.select('.x.nv-axis')
|
|
||||||
.attr('transform', 'translate(0, ' + height + ')')
|
|
||||||
.call(chartModel.xAxis);
|
|
||||||
|
|
||||||
graph.selectAll('.line')
|
|
||||||
.attr('d', chartModel.lines);
|
|
||||||
|
|
||||||
chartModel.update();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -9,16 +9,18 @@ function AutoSizeModule($window) {
|
|||||||
// fit into a single a page; assumes there are 2 rows
|
// fit into a single a page; assumes there are 2 rows
|
||||||
// of modules, with the available height being offset
|
// of modules, with the available height being offset
|
||||||
// by the navbar & the count summaries module
|
// by the navbar & the count summaries module
|
||||||
return function(scope, element) {
|
return function(scope, element, attrs) {
|
||||||
|
|
||||||
function adjustSizeInitially() {
|
|
||||||
adjustSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
function adjustSize() {
|
function adjustSize() {
|
||||||
var winHeight = $($window).height(),
|
if (attrs.graphType === "hostStatus") {
|
||||||
available_height = winHeight - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120;
|
if (element.parent().width() > 596) {
|
||||||
element.height(available_height/2);
|
element.height(596);
|
||||||
|
} else {
|
||||||
|
element.height(element.parent().width());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
element.height(320);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$($window).resize(adjustSize);
|
$($window).resize(adjustSize);
|
||||||
@ -30,8 +32,8 @@ function AutoSizeModule($window) {
|
|||||||
// This makes sure count-container div is loaded
|
// This makes sure count-container div is loaded
|
||||||
// by controllers/Home.js before we use it
|
// by controllers/Home.js before we use it
|
||||||
// to determine the available window height
|
// to determine the available window height
|
||||||
scope.$on('dashboardReady', function() {
|
scope.$on('resizeGraphs', function() {
|
||||||
adjustSizeInitially();
|
adjustSize();
|
||||||
});
|
});
|
||||||
|
|
||||||
};
|
};
|
||||||
6
awx/ui/static/js/dashboard/graphs/graph-helpers/main.js
Normal file
6
awx/ui/static/js/dashboard/graphs/graph-helpers/main.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import AutoSize from 'tower/dashboard/graphs/graph-helpers/auto-size.directive';
|
||||||
|
import AdjustGraphSize from 'tower/dashboard/graphs/graph-helpers/adjust-graph-size.service';
|
||||||
|
|
||||||
|
export default angular.module('DashboardGraphHelpers', [])
|
||||||
|
.directive('autoSizeModule', AutoSize)
|
||||||
|
.service('adjustGraphSize', AdjustGraphSize);
|
||||||
@ -1,14 +1,15 @@
|
|||||||
export default
|
export default
|
||||||
[ '$compile',
|
[ '$compile',
|
||||||
'$window',
|
'$window',
|
||||||
HostStatusGraph
|
'adjustGraphSize',
|
||||||
|
HostStatusGraph,
|
||||||
];
|
];
|
||||||
|
|
||||||
function HostStatusGraph($compile, $window) {
|
function HostStatusGraph($compile, $window, adjustGraphSize) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
link: link,
|
link: link,
|
||||||
templateUrl: '/static/partials/host_status_graph.html'
|
templateUrl: '/static/js/dashboard/graphs/host-status/host_status_graph.partial.html'
|
||||||
};
|
};
|
||||||
|
|
||||||
function link(scope, element, attr) {
|
function link(scope, element, attr) {
|
||||||
@ -20,12 +21,10 @@ function HostStatusGraph($compile, $window) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function adjustGraphSize() {
|
function adjustHostGraphSize() {
|
||||||
|
|
||||||
if (angular.isUndefined(host_pie_chart)) {
|
if (angular.isUndefined(host_pie_chart)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentHeight = element.parent().parent().height();
|
var parentHeight = element.parent().parent().height();
|
||||||
var toolbarHeight = element.find('.toolbar').height();
|
var toolbarHeight = element.find('.toolbar').height();
|
||||||
var container = element.find('svg').parent();
|
var container = element.find('svg').parent();
|
||||||
@ -38,10 +37,12 @@ function HostStatusGraph($compile, $window) {
|
|||||||
host_pie_chart.update();
|
host_pie_chart.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
angular.element($window).on('resize', adjustGraphSize);
|
angular.element($window).on('resize', adjustHostGraphSize);
|
||||||
|
$(".DashboardGraphs-graph--hostStatusGraph").resize(adjustHostGraphSize);
|
||||||
|
|
||||||
element.on('$destroy', function() {
|
element.on('$destroy', function() {
|
||||||
angular.element($window).off('resize', adjustGraphSize);
|
angular.element($window).off('resize', adjustHostGraphSize);
|
||||||
|
$(".DashboardGraphs-graph--hostStatusGraph").removeResize(adjustHostGraphSize);
|
||||||
});
|
});
|
||||||
|
|
||||||
function createGraph(data) {
|
function createGraph(data) {
|
||||||
@ -58,7 +59,7 @@ function HostStatusGraph($compile, $window) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
host_pie_chart = nv.models.pieChart()
|
host_pie_chart = nv.models.pieChart()
|
||||||
.margin({top: 5, right: 75, bottom: 25, left: 85})
|
.margin({bottom: 15})
|
||||||
.x(function(d) { return d.label; })
|
.x(function(d) { return d.label; })
|
||||||
.y(function(d) { return d.value; })
|
.y(function(d) { return d.value; })
|
||||||
.showLabels(true)
|
.showLabels(true)
|
||||||
@ -101,6 +102,7 @@ function HostStatusGraph($compile, $window) {
|
|||||||
element.find('svg').replaceWith(notFoundContainer);
|
element.find('svg').replaceWith(notFoundContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
<div class="graph">
|
||||||
|
<svg width="100%" height="100%" preserveAspectRatio="xMinYMin"></svg>
|
||||||
|
</div>
|
||||||
5
awx/ui/static/js/dashboard/graphs/host-status/main.js
Normal file
5
awx/ui/static/js/dashboard/graphs/host-status/main.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import HostStatusGraphDirective from 'tower/dashboard/graphs/host-status/host-status-graph.directive';
|
||||||
|
import DashboardGraphHelpers from 'tower/dashboard/graphs/graph-helpers/main';
|
||||||
|
|
||||||
|
export default angular.module('HostStatusGraph', [DashboardGraphHelpers.name])
|
||||||
|
.directive('hostStatusGraph', HostStatusGraphDirective);
|
||||||
@ -15,7 +15,7 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG
|
|||||||
scope: {
|
scope: {
|
||||||
data: '='
|
data: '='
|
||||||
},
|
},
|
||||||
templateUrl: '/static/partials/job_status_graph.html',
|
templateUrl: '/static/js/dashboard/graphs/job-status/job_status_graph.partial.html',
|
||||||
link: link
|
link: link
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,10 +38,10 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG
|
|||||||
scope.period = period;
|
scope.period = period;
|
||||||
scope.jobType = jobType;
|
scope.jobType = jobType;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createGraph(period, jobtype, data){
|
function createGraph(period, jobtype, data){
|
||||||
|
|
||||||
scope.period = period;
|
scope.period = period;
|
||||||
scope.jobType = jobtype;
|
scope.jobType = jobtype;
|
||||||
|
|
||||||
@ -73,7 +73,6 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG
|
|||||||
});
|
});
|
||||||
|
|
||||||
job_status_chart
|
job_status_chart
|
||||||
.margin({top: 5, right: 75, bottom: 40, left: 85}) //Adjust chart margins to give the x-axis some breathing room.
|
|
||||||
.x(function(d,i) { return i; })
|
.x(function(d,i) { return i; })
|
||||||
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
|
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
|
||||||
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
|
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
|
||||||
@ -120,17 +119,23 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG
|
|||||||
recreateGraph(period, job_type);
|
recreateGraph(period, job_type);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
job_status_chart.legend.margin({top: 1, right:0, left:24, bottom: 0});
|
||||||
|
|
||||||
adjustGraphSize(job_status_chart, element);
|
adjustGraphSize(job_status_chart, element);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onResize() {
|
function onResize() {
|
||||||
adjustGraphSize(job_status_chart, element);
|
adjustGraphSize(job_status_chart, element);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
angular.element($window).on('resize', onResize);
|
angular.element($window).on('resize', onResize);
|
||||||
|
$(".DashboardGraphs-graph--jobStatusGraph").resize(onResize);
|
||||||
|
|
||||||
element.on('$destroy', function() {
|
element.on('$destroy', function() {
|
||||||
angular.element($window).off('resize', onResize);
|
angular.element($window).off('resize', onResize);
|
||||||
|
$(".DashboardGraphs-graph--jobStatusGraph").removeResize(onResize);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (scope.removeGraphDataReady) {
|
if (scope.removeGraphDataReady) {
|
||||||
@ -39,12 +39,12 @@ function JobStatusGraphData(Rest, getBasePath, processErrors, $rootScope, $q) {
|
|||||||
setupWatcher: function(period, jobType) {
|
setupWatcher: function(period, jobType) {
|
||||||
this.destroyWatcher =
|
this.destroyWatcher =
|
||||||
$rootScope.$on('JobStatusChange-home', function() {
|
$rootScope.$on('JobStatusChange-home', function() {
|
||||||
getData(period, jobType).then(function(result) {
|
getData(period, jobType).then(function(result) {
|
||||||
$rootScope.
|
$rootScope.
|
||||||
$broadcast('DataReceived:JobStatusGraph',
|
$broadcast('DataReceived:JobStatusGraph',
|
||||||
result);
|
result);
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
get: function(period, jobType) {
|
get: function(period, jobType) {
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
<div class="DashboardGraphs-graphToolbar">
|
||||||
|
<div class="DashboardGraphs-filterDropdown">
|
||||||
|
Period:
|
||||||
|
<a id="period-dropdown" role="button" data-toggle="dropdown" data-target="#" href="/page.html">
|
||||||
|
Past Month<span class="caret"></span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ul class="dropdown-menu DashboardGraphs-filterDropdownItems
|
||||||
|
DashboardGraphs-filterDropdownItems--period" role="menu" aria-labelledby="period-dropdown">
|
||||||
|
<li>
|
||||||
|
<a class="n" id="day" >Past 24 Hours </a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="n" id="week">Past Week</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="n" id="month">Past Month</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="DashboardGraphs-filterDropdown">
|
||||||
|
Job Type:
|
||||||
|
<a id="type-dropdown" role="button" data-toggle="dropdown" data-target="#" href="/page.html">
|
||||||
|
All<span class="caret"></span>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ul class="dropdown-menu DashboardGraphs-filterDropdownItems
|
||||||
|
DashboardGraphs-filterDropdownItems--jobType" role="menu" aria-labelledby="type-dropdown">
|
||||||
|
<li>
|
||||||
|
<a class="m" id="all">All</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="m" id="inv_sync">Inventory Sync</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="m" id="scm_update">SCM Update</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a class="m" id="playbook_run">Playbook Run</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="graph">
|
||||||
|
<svg width="100%" height="100%"></svg>
|
||||||
|
</div>
|
||||||
8
awx/ui/static/js/dashboard/graphs/job-status/main.js
Normal file
8
awx/ui/static/js/dashboard/graphs/job-status/main.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import JobStatusGraphDirective from 'tower/dashboard/graphs/job-status/job-status-graph.directive';
|
||||||
|
import JobStatusGraphService from 'tower/dashboard/graphs/job-status/job-status-graph.service';
|
||||||
|
import DashboardGraphHelpers from 'tower/dashboard/graphs/graph-helpers/main';
|
||||||
|
import ApiLoader from 'tower/shared/api-loader';
|
||||||
|
|
||||||
|
export default angular.module('JobStatusGraph', [DashboardGraphHelpers.name, ApiLoader.name])
|
||||||
|
.directive('jobStatusGraph', JobStatusGraphDirective)
|
||||||
|
.service('jobStatusGraphData', JobStatusGraphService);
|
||||||
7
awx/ui/static/js/dashboard/graphs/main.js
Normal file
7
awx/ui/static/js/dashboard/graphs/main.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import hostStatus from 'tower/dashboard/graphs/host-status/main';
|
||||||
|
import jobStatus from 'tower/dashboard/graphs/job-status/main';
|
||||||
|
import dashboardGraphsDirective from 'tower/dashboard/graphs/dashboard-graphs.directive';
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('DashboardGraphModules', [hostStatus.name, jobStatus.name])
|
||||||
|
.directive('dashboardGraphs', dashboardGraphsDirective);
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
/** @define DashboardJobTemplates */
|
||||||
|
|
||||||
|
.DashboardJobTemplates {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
.DashboardJobTemplates--noJobTemplates {
|
||||||
|
color: #8d8d8d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-header {
|
||||||
|
flex: initial;
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-item {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding-bottom: 7px;
|
||||||
|
padding-top: 5px;
|
||||||
|
border-bottom: 1px solid #a9a9a9;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-item--snapRows {
|
||||||
|
flex: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-item:last-of-type {
|
||||||
|
border-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-seeMore {
|
||||||
|
padding-top: 11px;
|
||||||
|
padding-bottom: 11px;
|
||||||
|
width: ~"calc(100% + 32px)";
|
||||||
|
margin-left: -16px;
|
||||||
|
margin-bottom: -16px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 17px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #1778c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-seeMore:hover {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.DashboardJobTemplates-smartStatus {
|
||||||
|
flex: initial;
|
||||||
|
width: 88px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-name {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-name:hover {
|
||||||
|
font-weight: 700;
|
||||||
|
color: #2a6496;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.DashboardJobTemplates-launch {
|
||||||
|
font-size: 25px;
|
||||||
|
height: 28px;
|
||||||
|
width: 27px;
|
||||||
|
margin-left: 1px;
|
||||||
|
color: #1778c3;
|
||||||
|
margin-right: 13px;
|
||||||
|
flex: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-launch:hover {
|
||||||
|
margin-left: 0px;
|
||||||
|
width: 28px;
|
||||||
|
font-size: 28px;
|
||||||
|
color: #2a6496;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 710px) {
|
||||||
|
.DashboardJobTemplates-item {
|
||||||
|
padding-bottom: 9px;
|
||||||
|
padding-top: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-name {
|
||||||
|
font-size:19px;
|
||||||
|
border-left: 1px solid #a9a9a9;
|
||||||
|
padding-left: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-launch {
|
||||||
|
font-size: 35px;
|
||||||
|
height: 35px;
|
||||||
|
width: 30px;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobTemplates-launch:hover {
|
||||||
|
margin-left: 9px;
|
||||||
|
width: 31px;
|
||||||
|
font-size: 38px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
/* jshint unused: vars */
|
||||||
|
export default
|
||||||
|
[ "PlaybookRun",
|
||||||
|
function JobTemplatesList(PlaybookRun) {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
link: link,
|
||||||
|
scope: {
|
||||||
|
data: '='
|
||||||
|
},
|
||||||
|
templateUrl: '/static/js/dashboard/lists/job-templates/job-templates-list.partial.html'
|
||||||
|
};
|
||||||
|
|
||||||
|
function link(scope, element, attr) {
|
||||||
|
scope.$watch("data", function(data) {
|
||||||
|
if (data) {
|
||||||
|
if (data.length > 0) {
|
||||||
|
createList(data);
|
||||||
|
scope.noJobTemplates = false;
|
||||||
|
} else {
|
||||||
|
scope.noJobTemplates = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function createList(list) {
|
||||||
|
// smartStatus?, launchUrl, editUrl, name
|
||||||
|
scope.job_templates = _.map(list, function(job_template){ return {
|
||||||
|
recent_jobs: job_template.summary_fields.recent_jobs,
|
||||||
|
launch_url: job_template.url,
|
||||||
|
edit_url: job_template.url.replace('api/v1', '#'),
|
||||||
|
name: job_template.name,
|
||||||
|
id: job_template.id
|
||||||
|
}; });
|
||||||
|
|
||||||
|
scope.snapRows = (list.length < 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.isSuccessful = function (status) {
|
||||||
|
return (status === "successful");
|
||||||
|
};
|
||||||
|
|
||||||
|
scope.launchJobTemplate = function(jobTemplateId){
|
||||||
|
PlaybookRun({ scope: scope, id: jobTemplateId });
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}];
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<div class="DashboardJobTemplates" ng-hide="noJobTemplates">
|
||||||
|
<h3 class="DashboardJobTemplates-header">
|
||||||
|
Recently Used Job Templates
|
||||||
|
</h3>
|
||||||
|
<div class="DashboardJobTemplates-container">
|
||||||
|
<div class="DashboardJobTemplates-item"
|
||||||
|
ng-class="{'DashboardJobTemplates-item--snapRows': {{ snapRows }}}"
|
||||||
|
ng-repeat="job_template in job_templates">
|
||||||
|
<i class="fa fa-rocket
|
||||||
|
DashboardJobTemplates-launch"
|
||||||
|
ng-click="launchJobTemplate(job_template.id)"></i>
|
||||||
|
<a href="#/job_templates/{{ job_template.id }}" class="DashboardJobTemplates-name">
|
||||||
|
{{ job_template.name }}
|
||||||
|
</a>
|
||||||
|
<aw-smart-status jobs="job_template.recent_jobs" class="DashboardJobTemplates-smartStatus"></aw-smart-status>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="/#/job_templates" class="DashboardJobTemplates-seeMore">
|
||||||
|
See all job templates
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="DashboardJobTemplates DashboardJobTemplates--noJobTemplates" ng-show="noJobTemplates">
|
||||||
|
<h3 class="DashboardJobTemplates-header">
|
||||||
|
Recent Job Runs
|
||||||
|
</h3>
|
||||||
|
<p>It doesn't seem like you have used any job templates.<br />
|
||||||
|
You can create a job template <a href="#/job_templates/add">here</a>.</p>
|
||||||
|
</div>
|
||||||
6
awx/ui/static/js/dashboard/lists/job-templates/main.js
Normal file
6
awx/ui/static/js/dashboard/lists/job-templates/main.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import JobTemplatesListDirective from 'tower/dashboard/lists/job-templates/job-templates-list.directive';
|
||||||
|
import systemStatus from 'tower/smart-status/main';
|
||||||
|
import jobSubmissionHelper from 'tower/helpers/JobSubmission';
|
||||||
|
|
||||||
|
export default angular.module('JobTemplatesList', [systemStatus.name, jobSubmissionHelper.name])
|
||||||
|
.directive('jobTemplatesList', JobTemplatesListDirective);
|
||||||
113
awx/ui/static/js/dashboard/lists/jobs/jobs-list.block.less
Normal file
113
awx/ui/static/js/dashboard/lists/jobs/jobs-list.block.less
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/** @define DashboardJobs */
|
||||||
|
|
||||||
|
.DashboardJobs {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs--noJobs {
|
||||||
|
color: #8d8d8d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-header {
|
||||||
|
flex: initial;
|
||||||
|
margin-top: 0;
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-container {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
padding-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-item {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding-bottom: 0;
|
||||||
|
padding-top: 0;
|
||||||
|
border-bottom: 1px solid #a9a9a9;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.DashboardJobs-item--snapRows {
|
||||||
|
flex: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-itemLink {
|
||||||
|
flex: 2;
|
||||||
|
display: flex;
|
||||||
|
padding-bottom: 9px;
|
||||||
|
padding-top: 7px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-status {
|
||||||
|
flex: initial;
|
||||||
|
height: 18px;
|
||||||
|
width: 23px;
|
||||||
|
font-size: 18px;
|
||||||
|
margin-bottom: -3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-nameContainer {
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-time {
|
||||||
|
flex: initial;
|
||||||
|
text-align: right;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
margin-left: 10px;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-itemLink:hover {
|
||||||
|
.DashboardJobs-nameContainer,
|
||||||
|
.DashboardJobs-time {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-status--success {
|
||||||
|
color: #5DF370;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-status--failed {
|
||||||
|
color: #FF1105;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-item:last-of-type {
|
||||||
|
border-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-seeMore {
|
||||||
|
padding-top: 11px;
|
||||||
|
padding-bottom: 11px;
|
||||||
|
width: ~"calc(100% + 32px)";
|
||||||
|
margin-left: -16px;
|
||||||
|
margin-bottom: -16px;
|
||||||
|
border-bottom-left-radius: 4px;
|
||||||
|
border-bottom-right-radius: 4px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 17px;
|
||||||
|
text-align: center;
|
||||||
|
background-color: #1778c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.DashboardJobs-seeMore:hover {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 710px) {
|
||||||
|
.DashboardJobs-nameContainer {
|
||||||
|
font-size: 19px;
|
||||||
|
}
|
||||||
|
}
|
||||||
42
awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js
Normal file
42
awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
/* jshint unused: vars */
|
||||||
|
export default
|
||||||
|
[function JobsList() {
|
||||||
|
return {
|
||||||
|
restrict: 'E',
|
||||||
|
link: link,
|
||||||
|
scope: {
|
||||||
|
data: '='
|
||||||
|
},
|
||||||
|
templateUrl: '/static/js/dashboard/lists/jobs/jobs-list.partial.html'
|
||||||
|
};
|
||||||
|
|
||||||
|
function link(scope, element, attr) {
|
||||||
|
scope.$watch("data", function(data) {
|
||||||
|
if (data) {
|
||||||
|
if (data.length > 0) {
|
||||||
|
createList(data);
|
||||||
|
scope.noJobs = false;
|
||||||
|
} else {
|
||||||
|
scope.noJobs = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function createList(list) {
|
||||||
|
// detailsUrl, status, name, time
|
||||||
|
scope.jobs = _.map(list, function(job){
|
||||||
|
return {
|
||||||
|
detailsUrl: job.url.replace("api/v1", "#"),
|
||||||
|
status: job.status,
|
||||||
|
name: job.name,
|
||||||
|
time: moment(job.finished).fromNow()
|
||||||
|
}; });
|
||||||
|
|
||||||
|
scope.snapRows = (list.length < 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.isSuccessful = function (status) {
|
||||||
|
return (status === "successful");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}];
|
||||||
35
awx/ui/static/js/dashboard/lists/jobs/jobs-list.partial.html
Normal file
35
awx/ui/static/js/dashboard/lists/jobs/jobs-list.partial.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<div class="DashboardJobs" ng-hide="noJobs">
|
||||||
|
<h3 class="DashboardJobs-header">
|
||||||
|
Recent Job Runs
|
||||||
|
</h3>
|
||||||
|
<div class="DashboardJobs-container">
|
||||||
|
<div class="DashboardJobs-item"
|
||||||
|
ng-class="{'DashboardJobs-item--snapRows': {{ snapRows }}}"
|
||||||
|
ng-repeat="job in jobs">
|
||||||
|
<a ng-href="{{ job.detailsUrl }}"
|
||||||
|
class="DashboardJobs-itemLink">
|
||||||
|
<i class="fa
|
||||||
|
DashboardJobs-status"
|
||||||
|
ng-class="{'DashboardJobs-status--success icon-job-successful': isSuccessful(job.status),
|
||||||
|
'DashboardJobs-status--failed icon-job-failed': !isSuccessful(job.status)}">
|
||||||
|
</i>
|
||||||
|
<span class="DashboardJobs-nameContainer">
|
||||||
|
{{job.name}}
|
||||||
|
</span>
|
||||||
|
<div class="DashboardJobs-time">
|
||||||
|
{{ job.time }}
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a href="/#/jobs" class="DashboardJobs-seeMore">
|
||||||
|
See all job runs
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="DashboardJobs DashboardJobs--noJobs" ng-show="noJobs">
|
||||||
|
<h3 class="DashboardJobs-header">
|
||||||
|
Recent Job Runs
|
||||||
|
</h3>
|
||||||
|
<p>It doesn't seem like you have any recent job runs.</p>
|
||||||
|
</div>
|
||||||
4
awx/ui/static/js/dashboard/lists/jobs/main.js
Normal file
4
awx/ui/static/js/dashboard/lists/jobs/main.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import JobsListDirective from 'tower/dashboard/lists/jobs/jobs-list.directive';
|
||||||
|
|
||||||
|
export default angular.module('JobsList', [])
|
||||||
|
.directive('jobsList', JobsListDirective);
|
||||||
5
awx/ui/static/js/dashboard/lists/main.js
Normal file
5
awx/ui/static/js/dashboard/lists/main.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import jobTemplates from 'tower/dashboard/lists/job-templates/main';
|
||||||
|
import jobs from 'tower/dashboard/lists/jobs/main';
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('DashboardListsModules', [jobTemplates.name, jobs.name]);
|
||||||
8
awx/ui/static/js/dashboard/main.js
Normal file
8
awx/ui/static/js/dashboard/main.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import dashboardCounts from 'tower/dashboard/counts/main';
|
||||||
|
import dashboardGraphs from 'tower/dashboard/graphs/main';
|
||||||
|
import dashboardLists from 'tower/dashboard/lists/main';
|
||||||
|
import dashboardDirective from 'tower/dashboard/dashboard.directive';
|
||||||
|
|
||||||
|
export default
|
||||||
|
angular.module('dashboard', [dashboardCounts.name, dashboardGraphs.name, dashboardLists.name])
|
||||||
|
.directive('dashboard', dashboardDirective);
|
||||||
@ -1,12 +0,0 @@
|
|||||||
import JobStatusGraph from 'tower/directives/job-status-graph';
|
|
||||||
import HostCountGraph from 'tower/directives/host-count-graph';
|
|
||||||
import HostStatusGraph from 'tower/directives/host-status-graph';
|
|
||||||
import AutoSizeModule from 'tower/directives/auto-size-module';
|
|
||||||
import AdjustGraphSize from 'tower/services/adjust-graph-size';
|
|
||||||
|
|
||||||
export default angular.module('DashboardGraphs', [])
|
|
||||||
.directive('jobStatusGraph', JobStatusGraph)
|
|
||||||
.directive('hostCountGraph', HostCountGraph)
|
|
||||||
.directive('hostStatusGraph', HostStatusGraph)
|
|
||||||
.directive('autoSizeModule', AutoSizeModule)
|
|
||||||
.service('adjustGraphSize', AdjustGraphSize);
|
|
||||||
@ -1,124 +0,0 @@
|
|||||||
export default
|
|
||||||
[ 'adjustGraphSize',
|
|
||||||
'$window',
|
|
||||||
HostCountGraph
|
|
||||||
];
|
|
||||||
|
|
||||||
function HostCountGraph(adjustGraphSize, $window) {
|
|
||||||
|
|
||||||
return {
|
|
||||||
restrict: 'E',
|
|
||||||
templateUrl: '/static/partials/host_count_graph.html',
|
|
||||||
link: link
|
|
||||||
};
|
|
||||||
|
|
||||||
function link(scope, element, attr) {
|
|
||||||
var license_graph;
|
|
||||||
|
|
||||||
scope.$watch(attr.data, function(data) {
|
|
||||||
|
|
||||||
if(!data) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
createGraph(data.hosts, data.license);
|
|
||||||
});
|
|
||||||
|
|
||||||
function onResize() {
|
|
||||||
|
|
||||||
if(!license_graph) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
adjustGraphSize(license_graph, element);
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.element($window).on('resize', onResize);
|
|
||||||
|
|
||||||
element.on('$destroy', function() {
|
|
||||||
angular.element($window).off('resize', onResize);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function createGraph(data, license) {
|
|
||||||
//url = getBasePath('dashboard')+'graphs/';
|
|
||||||
var graphData = [
|
|
||||||
{ "key" : "Hosts" ,
|
|
||||||
"color" : "#1778c3",
|
|
||||||
"values": data.hosts
|
|
||||||
},
|
|
||||||
{ "key" : "License" ,
|
|
||||||
"color" : "#171717",
|
|
||||||
"values": data.hosts
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
graphData.map(function(series) {
|
|
||||||
if(series.key==="Hosts"){
|
|
||||||
series.values = series.values.map(function(d) {
|
|
||||||
return {
|
|
||||||
x: d[0],
|
|
||||||
y: d[1]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if(series.key==="License"){
|
|
||||||
series.values = series.values.map(function(d) {
|
|
||||||
return {
|
|
||||||
x: d[0],
|
|
||||||
y: license
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
return series;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
var width = $('.graph-container').width(), // nv.utils.windowSize().width/3,
|
|
||||||
height = $('.graph-container').height()*0.6; //nv.utils.windowSize().height/5,
|
|
||||||
license_graph = nv.models.lineChart()
|
|
||||||
.margin({top: 15, right: 75, bottom: 40, left: 85})
|
|
||||||
.x(function(d,i) { return i ;})
|
|
||||||
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
|
|
||||||
.duration(350) //how fast do you want the lines to transition?
|
|
||||||
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
|
|
||||||
.showYAxis(true) //Show the y-axis
|
|
||||||
.showXAxis(true) //Show the x-axis
|
|
||||||
;
|
|
||||||
|
|
||||||
license_graph.xAxis
|
|
||||||
.axisLabel("Time")
|
|
||||||
.tickFormat(function(d) {
|
|
||||||
var dx = graphData[0].values[d] && graphData[0].values[d].x || 0;
|
|
||||||
return dx ? d3.time.format('%m/%d')(new Date(Number(dx+'000'))) : '';
|
|
||||||
});
|
|
||||||
|
|
||||||
license_graph.yAxis //Chart y-axis settings
|
|
||||||
.axisLabel('Hosts')
|
|
||||||
.tickFormat(d3.format('.f'));
|
|
||||||
|
|
||||||
d3.select(element.find('svg')[0])
|
|
||||||
.datum(graphData).transition()
|
|
||||||
.attr('width', width)
|
|
||||||
.attr('height', height)
|
|
||||||
.duration(500)
|
|
||||||
.call(license_graph)
|
|
||||||
.style({
|
|
||||||
"font-family": 'Open Sans',
|
|
||||||
"font-style": "normal",
|
|
||||||
"font-weight":400,
|
|
||||||
"src": "url(/static/fonts/OpenSans-Regular.ttf)"
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
scope.$emit('WidgetLoaded');
|
|
||||||
|
|
||||||
adjustGraphSize(license_graph, element);
|
|
||||||
|
|
||||||
return license_graph;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -744,7 +744,7 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm,
|
|||||||
launch_url,
|
launch_url,
|
||||||
html;
|
html;
|
||||||
scope.job_template_id = id;
|
scope.job_template_id = id;
|
||||||
if (base === 'job_templates' || base === 'portal' || base === 'inventories') {
|
if (base === 'job_templates' || base === 'portal' || base === 'inventories' || base === 'home') {
|
||||||
url = GetBasePath('job_templates') + id + '/launch/';
|
url = GetBasePath('job_templates') + id + '/launch/';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -777,7 +777,8 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm,
|
|||||||
}
|
}
|
||||||
scope.removePlaybookLaunchFinished = scope.$on('PlaybookLaunchFinished', function(e, data) {
|
scope.removePlaybookLaunchFinished = scope.$on('PlaybookLaunchFinished', function(e, data) {
|
||||||
var job = data.job || data.system_job;
|
var job = data.job || data.system_job;
|
||||||
if((scope.portalMode===false || scope.$parent.portalMode===false ) && Empty(data.system_job)){
|
if((scope.portalMode===false || scope.$parent.portalMode===false ) && Empty(data.system_job) ||
|
||||||
|
(base === 'home')){
|
||||||
$location.path('/jobs/' + job);
|
$location.path('/jobs/' + job);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +0,0 @@
|
|||||||
import JobStatusGraphData from 'tower/services/job-status-graph-data';
|
|
||||||
import HostCountGraphData from 'tower/services/host-count-graph-data';
|
|
||||||
|
|
||||||
export default
|
|
||||||
angular.module('DataServices', ['ApiLoader'])
|
|
||||||
.service('jobStatusGraphData', JobStatusGraphData)
|
|
||||||
.service('hostCountGraphData', HostCountGraphData);
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
export default
|
|
||||||
[ "Rest",
|
|
||||||
"GetBasePath",
|
|
||||||
"ProcessErrors",
|
|
||||||
"$q",
|
|
||||||
HostCountGraphData
|
|
||||||
];
|
|
||||||
|
|
||||||
function HostCountGraphData(Rest, getBasePath, processErrors, $q) {
|
|
||||||
|
|
||||||
function pluck(property, promise) {
|
|
||||||
return promise.then(function(value) {
|
|
||||||
return value[property];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLicenseData() {
|
|
||||||
var url = getBasePath('config');
|
|
||||||
Rest.setUrl(url);
|
|
||||||
return Rest.get()
|
|
||||||
.then(function (data){
|
|
||||||
var license = data.data.license_info.instance_count;
|
|
||||||
return license;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHostData() {
|
|
||||||
var url = getBasePath('dashboard')+'graphs/inventory/';
|
|
||||||
Rest.setUrl(url);
|
|
||||||
return pluck('data', Rest.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
get: function() {
|
|
||||||
return $q.all({
|
|
||||||
license: getLicenseData(),
|
|
||||||
hosts: getHostData()
|
|
||||||
}).catch(function (response) {
|
|
||||||
var errorMessage = 'Failed to get: ' + response.url + ' GET returned: ' + response.status;
|
|
||||||
processErrors(null, response.data, response.status, null, { hdr: 'Error!',
|
|
||||||
msg: errorMessage
|
|
||||||
});
|
|
||||||
return $q.reject(response);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@ -6,14 +6,15 @@ export default [ function() {
|
|||||||
},
|
},
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
link: function (scope, element){
|
link: function (scope, element){
|
||||||
|
|
||||||
scope.formatter = function(sparklines, options, point){
|
scope.formatter = function(sparklines, options, point){
|
||||||
var status = options.userOptions.tooltipValueLookups.status[point.offset];
|
var status = options.userOptions.tooltipValueLookups.status[point.offset];
|
||||||
//capitalize first letter
|
//capitalize first letter
|
||||||
status = status.charAt(0).toUpperCase() + status.slice(1);
|
if (status) {
|
||||||
return "<div class=\"smart-status-tooltip\">Job ID: " +
|
status = status.charAt(0).toUpperCase() + status.slice(1);
|
||||||
options.userOptions.tooltipValueLookups.jobs[point.offset] +
|
return "<div class=\"smart-status-tooltip\">Job ID: " +
|
||||||
"<br>Status: <span style=\"color: " + point.color + "\">●</span>"+status+"</div>" ;
|
options.userOptions.tooltipValueLookups.jobs[point.offset] +
|
||||||
|
"<br>Status: <span style=\"color: " + point.color + "\">●</span>"+status+"</div>" ;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
element.sparkline(scope.sparkArray, {
|
element.sparkline(scope.sparkArray, {
|
||||||
|
|||||||
@ -1,12 +1,6 @@
|
|||||||
import "tower/widgets/DashboardCounts";
|
|
||||||
import "tower/widgets/DashboardJobs";
|
|
||||||
import "tower/widgets/HostGraph";
|
|
||||||
import "tower/widgets/HostPieChart";
|
|
||||||
import "tower/widgets/InventorySyncStatus";
|
import "tower/widgets/InventorySyncStatus";
|
||||||
import "tower/widgets/JobStatus";
|
import "tower/widgets/JobStatus";
|
||||||
import "tower/widgets/JobStatusGraph";
|
|
||||||
import "tower/widgets/ObjectCount";
|
import "tower/widgets/ObjectCount";
|
||||||
import "tower/widgets/PortalJobs";
|
import "tower/widgets/PortalJobs";
|
||||||
import "tower/widgets/SCMSyncStatus";
|
import "tower/widgets/SCMSyncStatus";
|
||||||
import "tower/widgets/Stream";
|
import "tower/widgets/Stream";
|
||||||
|
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
/*********************************************
|
|
||||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @ngdoc overview
|
|
||||||
* @name widgets
|
|
||||||
* @description Various widgets, including widgets on the dashboard
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name widgets.function:DashboardCounts
|
|
||||||
* @description
|
|
||||||
* The dashboard widget with stats across the top
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
angular.module('DashboardCountsWidget', ['RestServices', 'Utilities'])
|
|
||||||
.factory('DashboardCounts', ['$rootScope', '$compile', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait',
|
|
||||||
function ($rootScope, $compile) {
|
|
||||||
return function (params) {
|
|
||||||
|
|
||||||
var scope = params.scope,
|
|
||||||
target = params.target,
|
|
||||||
dashboard = params.dashboard,
|
|
||||||
html, element;
|
|
||||||
|
|
||||||
|
|
||||||
html = "<div class=\"container\" >\n";
|
|
||||||
|
|
||||||
html = "<div id=\"count-container\" class=\"count-container row\">\n";
|
|
||||||
html += "<div class=\"h2 col-xs-4 col-sm-2 text-center\"><a href=\"/#/home/hosts\">"+ dashboard.hosts.total+"</a><br><h6>Hosts</h6></div>\n";
|
|
||||||
html += "<div class=\"h2 col-xs-4 col-sm-2 text-center\"><a href=\"/#/home/hosts/?has_active_failures=true\" id=\"failed-hosts\">"+dashboard.hosts.failed+"</a><br><h6>Failed Hosts</h6></div>\n";
|
|
||||||
html += "<div class=\"h2 col-xs-4 col-sm-2 text-center\"><a href=\"/#/inventories\">"+dashboard.inventories.total+"</a><br><h6>Inventories</h6></div>\n";
|
|
||||||
html += "<div class=\"h2 col-xs-4 col-sm-2 text-center\"><a href=\"/#/inventories/?inventory_sources_with_failures\" id=\"failed-inventories\">"+dashboard.inventories.inventory_failed+"</a><br><h6>Inventory Sync Failures</h6></div>\n";
|
|
||||||
html += "<div class=\"h2 col-xs-4 col-sm-2 text-center\"><a href=\"/#/projects\">"+dashboard.projects.total+"</a><br><h6>Projects</h6></div>\n";
|
|
||||||
html += "<div class=\"h2 col-xs-4 col-sm-2 text-center\"><a href=\"/#/projects/?status=failed\" id=\"failed-projects\">"+dashboard.projects.failed+"</a><br><h6>Project Sync Failures</h6></div>\n";
|
|
||||||
// html += "<div class=\"h2 col-xs-4 col-sm-2 text-center\"><a href=/#/users>"+dashboard.users.total+"</a></div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
|
|
||||||
element = angular.element(document.getElementById(target));
|
|
||||||
element.html(html);
|
|
||||||
$compile(element)(scope);
|
|
||||||
if(dashboard.hosts.failed>0 ){
|
|
||||||
$('#failed-hosts').replaceWith("<a style=\"color: #ff5850\" href=\"/#/home/hosts/?has_active_failures=true\" id=\"failed-hosts\">"+dashboard.hosts.failed+"</a>");
|
|
||||||
}
|
|
||||||
if(dashboard.inventories.inventory_failed>0 ){
|
|
||||||
$('#failed-inventories').replaceWith("<a style=\"color: #ff5850\" href=/#/inventories/?inventory_sources_with_failures id=\"failed-inventories\">"+dashboard.inventories.inventory_failed+"</a>");
|
|
||||||
}
|
|
||||||
if(dashboard.projects.failed>0 ){
|
|
||||||
$('#failed-projects').replaceWith("<a style=\"color: #ff5850\" href=\"/#/projects/?status=failed\" id=\"failed-projects\">"+dashboard.projects.failed+"</a>");
|
|
||||||
}
|
|
||||||
scope.$emit('WidgetLoaded');
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
@ -1,183 +0,0 @@
|
|||||||
/*********************************************
|
|
||||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name widgets.function:DashboardJobs
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
angular.module('DashboardJobsWidget', ['RestServices', 'Utilities'])
|
|
||||||
.factory('DashboardJobs', ['$rootScope', '$compile', 'LoadSchedulesScope', 'LoadJobsScope', 'JobsList', 'ScheduledJobsList', 'GetChoices', 'GetBasePath',
|
|
||||||
function ($rootScope, $compile, LoadSchedulesScope, LoadJobsScope, JobsList, ScheduledJobsList, GetChoices, GetBasePath) {
|
|
||||||
return function (params) {
|
|
||||||
var scope = params.scope,
|
|
||||||
target = params.target,
|
|
||||||
choicesCount = 0,
|
|
||||||
listCount = 0,
|
|
||||||
jobs_scope = scope.$new(true),
|
|
||||||
scheduled_scope = scope.$new(true),
|
|
||||||
max_rows,
|
|
||||||
html, e;
|
|
||||||
|
|
||||||
html = '';
|
|
||||||
html += "<div class=\"dashboard-jobs-list-container\">\n";
|
|
||||||
html += "<ul id=\"job_status_tabs\" class=\"nav nav-tabs\">\n";
|
|
||||||
html += "<li class=\"active\"><a id=\"active_jobs_link\" ng-click=\"toggleTab($event, 'active_jobs_link', 'job_status_tabs')\"\n";
|
|
||||||
html += " href=\"#active-jobs-tab\" data-toggle=\"tab\">Jobs</a></li>\n";
|
|
||||||
html += "<li><a id=\"scheduled_jobs_link\" ng-click=\"toggleTab($event, 'scheduled_jobs_link', 'job_status_tabs')\"\n";
|
|
||||||
html += "href=\"#scheduled-jobs-tab\" data-toggle=\"tab\">Schedule</a></li>\n";
|
|
||||||
html += "</ul>\n";
|
|
||||||
html += "<div id=\"dashboard-tab-content\" class=\"tab-content \">\n";
|
|
||||||
html += "<div class=\"tab-pane active\" id=\"active-jobs-tab\">\n";
|
|
||||||
html += "<div class=\"row search-row\">\n";
|
|
||||||
html += "<div class=\"col-lg-6 col-md-6\" id=\"active-jobs-search-container\"></div>\n";
|
|
||||||
html += "</div>\n"; //row
|
|
||||||
html += "<div class=\"job-list\" id=\"active-jobs-container\">\n";
|
|
||||||
html += "<div id=\"active-jobs\" class=\"job-list-target\"></div>\n";
|
|
||||||
html += "</div>\n"; //list
|
|
||||||
html += "</div>\n"; //active-jobs-tab
|
|
||||||
html += "<div class=\"tab-pane\" id=\"scheduled-jobs-tab\"></div>\n";
|
|
||||||
html += "</div>\n"; // jobs-list-container
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
e = angular.element(document.getElementById(target));
|
|
||||||
e.html(html);
|
|
||||||
$compile(e)(scope);
|
|
||||||
|
|
||||||
$rootScope.$on('JobStatusChange-home', function() {
|
|
||||||
jobs_scope.refreshJobs();
|
|
||||||
});
|
|
||||||
|
|
||||||
if (scope.removeListLoaded) {
|
|
||||||
scope.removeListLoaded();
|
|
||||||
}
|
|
||||||
scope.removeListLoaded = scope.$on('listLoaded', function() {
|
|
||||||
listCount++;
|
|
||||||
if (listCount === 1) {
|
|
||||||
//api_complete = true;
|
|
||||||
scope.$emit('WidgetLoaded', "dashboard_jobs", jobs_scope, scheduled_scope);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// After all choices are ready, load up the lists and populate the page
|
|
||||||
if (scope.removeBuildJobsList) {
|
|
||||||
scope.removeBuildJobsList();
|
|
||||||
}
|
|
||||||
scope.removeBuildJobsList = scope.$on('buildJobsList', function() {
|
|
||||||
if (JobsList.fields.type) {
|
|
||||||
JobsList.fields.type.searchOptions = scope.type_choices;
|
|
||||||
}
|
|
||||||
LoadJobsScope({
|
|
||||||
parent_scope: scope,
|
|
||||||
scope: jobs_scope,
|
|
||||||
list: JobsList,
|
|
||||||
id: 'active-jobs',
|
|
||||||
url: GetBasePath('unified_jobs') + '?status__in=pending,running,completed,failed,successful,error,canceled',
|
|
||||||
pageSize: max_rows,
|
|
||||||
spinner: false
|
|
||||||
});
|
|
||||||
LoadSchedulesScope({
|
|
||||||
parent_scope: scope,
|
|
||||||
scope: scheduled_scope,
|
|
||||||
list: ScheduledJobsList,
|
|
||||||
id: 'scheduled-jobs-tab',
|
|
||||||
url: GetBasePath('schedules') + '?next_run__isnull=false',
|
|
||||||
pageSize: max_rows,
|
|
||||||
spinner: false
|
|
||||||
});
|
|
||||||
|
|
||||||
$(window).resize(_.debounce(function() {
|
|
||||||
resizeDashboardJobsWidget();
|
|
||||||
}, 500));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (scope.removeChoicesReady) {
|
|
||||||
scope.removeChoicesReady();
|
|
||||||
}
|
|
||||||
scope.removeChoicesReady = scope.$on('choicesReady', function() {
|
|
||||||
choicesCount++;
|
|
||||||
if (choicesCount === 2) {
|
|
||||||
setDashboardJobsHeight();
|
|
||||||
scope.$emit('buildJobsList');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
GetChoices({
|
|
||||||
scope: scope,
|
|
||||||
url: GetBasePath('unified_jobs'),
|
|
||||||
field: 'status',
|
|
||||||
variable: 'status_choices',
|
|
||||||
callback: 'choicesReady'
|
|
||||||
});
|
|
||||||
|
|
||||||
GetChoices({
|
|
||||||
scope: scope,
|
|
||||||
url: GetBasePath('unified_jobs'),
|
|
||||||
field: 'type',
|
|
||||||
variable: 'type_choices',
|
|
||||||
callback: 'choicesReady'
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Set the height of each container and calc max number of rows containers can hold
|
|
||||||
function setDashboardJobsHeight() {
|
|
||||||
var docw = $(window).width(),
|
|
||||||
box_height, available_height, search_row, page_row, height, header, row_height;
|
|
||||||
|
|
||||||
available_height = Math.floor(($(window).height() - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120)/2);
|
|
||||||
$('.dashboard-jobs-list-container').height(available_height);
|
|
||||||
search_row = Math.max($('.search-row:eq(0)').outerHeight(), 50);
|
|
||||||
page_row = Math.max($('.page-row:eq(0)').outerHeight(), 33);
|
|
||||||
header = Math.max($('#completed_jobs_table thead').height(), 41);
|
|
||||||
height = Math.floor(available_height) - header - page_row - search_row -30 ;
|
|
||||||
// if (docw < 765 && docw >= 493) {
|
|
||||||
// row_height = 27;
|
|
||||||
// }
|
|
||||||
if (docw < 480) {
|
|
||||||
row_height = 87;
|
|
||||||
}
|
|
||||||
else if (docw < 767) {
|
|
||||||
row_height = 44;
|
|
||||||
}
|
|
||||||
else if (docw < 926) {
|
|
||||||
row_height = 87;
|
|
||||||
}
|
|
||||||
else if (docw < 1200) {
|
|
||||||
row_height = 44;
|
|
||||||
}
|
|
||||||
else if (docw < 1415) {
|
|
||||||
row_height = 55;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
row_height = 44;
|
|
||||||
}
|
|
||||||
max_rows = Math.floor(height / row_height);
|
|
||||||
if (max_rows < 5){
|
|
||||||
box_height = header+page_row + search_row + 40 + (5 * row_height);
|
|
||||||
if (docw < 1140) {
|
|
||||||
box_height += 40;
|
|
||||||
}
|
|
||||||
$('.dashboard-jobs-list-container').height(box_height);
|
|
||||||
max_rows = 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set container height and return the number of allowed rows
|
|
||||||
function resizeDashboardJobsWidget() {
|
|
||||||
setDashboardJobsHeight();
|
|
||||||
jobs_scope[JobsList.iterator + '_page_size'] = max_rows;
|
|
||||||
jobs_scope.changePageSize(JobsList.name, JobsList.iterator, false);
|
|
||||||
scheduled_scope[ScheduledJobsList.iterator + '_page_size'] = max_rows;
|
|
||||||
scheduled_scope.changePageSize(ScheduledJobsList.name, ScheduledJobsList.iterator, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
@ -1,180 +0,0 @@
|
|||||||
/*********************************************
|
|
||||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name widgets.function:HostGraph
|
|
||||||
* @description
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
angular.module('HostGraphWidget', ['RestServices', 'Utilities'])
|
|
||||||
.factory('HostGraph', ['$rootScope', '$compile', '$location', 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait',
|
|
||||||
function ($rootScope, $compile, $location, Rest, GetBasePath, ProcessErrors) {
|
|
||||||
return function (params) {
|
|
||||||
|
|
||||||
var scope = params.scope,
|
|
||||||
target = params.target,
|
|
||||||
html, element, url, license, license_graph;
|
|
||||||
|
|
||||||
|
|
||||||
// html = "<div class=\"graph-container\">\n";
|
|
||||||
html ="<div class=\"row\">\n";
|
|
||||||
html += "<div class=\"h6 col-xs-8 text-center\"><b>Host Count</b></div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html +="<div class=\"row\">\n";
|
|
||||||
html += "<div class=\"host-count-graph\"><svg></svg></div>\n";
|
|
||||||
|
|
||||||
// html += "</div>\n";
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
element = angular.element(document.getElementById(target));
|
|
||||||
element.html(html);
|
|
||||||
$compile(element)(scope);
|
|
||||||
|
|
||||||
url = GetBasePath('config');
|
|
||||||
|
|
||||||
if (scope.removeResizeHostGraph) {
|
|
||||||
scope.removeResizeHostGraph();
|
|
||||||
}
|
|
||||||
scope.removeResizeHostGraph= scope.$on('ResizeHostGraph', function () {
|
|
||||||
if($(window).width()<500){
|
|
||||||
$('.graph-container').height(300);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
var winHeight = $(window).height(),
|
|
||||||
available_height = winHeight - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120;
|
|
||||||
$('.graph-container').height(available_height/2);
|
|
||||||
license_graph.update();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Rest.setUrl(url);
|
|
||||||
Rest.get()
|
|
||||||
.success(function (data){
|
|
||||||
license = data.license_info.instance_count;
|
|
||||||
scope.$emit('licenseCountReady', license);
|
|
||||||
})
|
|
||||||
.error(function (data, status) {
|
|
||||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Failed to get: ' + url + ' GET returned: ' + status });
|
|
||||||
});
|
|
||||||
|
|
||||||
if (scope.removeLicenseCountReady) {
|
|
||||||
scope.removeLicenseCountReady();
|
|
||||||
}
|
|
||||||
scope.removeLicenseCountReady = scope.$on('licenseCountReady', function (e, license) {
|
|
||||||
url = GetBasePath('dashboard')+'graphs/inventory/';
|
|
||||||
Rest.setUrl(url);
|
|
||||||
Rest.get()
|
|
||||||
.success(function (data) {
|
|
||||||
scope.$emit('hostDataReady', data, license);
|
|
||||||
})
|
|
||||||
.error(function (data, status) {
|
|
||||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Failed to get: ' + url + ' GET returned: ' + status });
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
if (scope.removeHostDataReady) {
|
|
||||||
scope.removeHostDataReady();
|
|
||||||
}
|
|
||||||
scope.removeHostDataReady = scope.$on('hostDataReady', function (e, data, license) {
|
|
||||||
|
|
||||||
//url = GetBasePath('dashboard')+'graphs/';
|
|
||||||
var graphData = [
|
|
||||||
{
|
|
||||||
"key" : "Hosts" ,
|
|
||||||
"color" : "#1778c3",
|
|
||||||
"values": data.hosts
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "License" ,
|
|
||||||
"color" : "#171717",
|
|
||||||
"values": data.hosts
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
graphData.map(function(series) {
|
|
||||||
if(series.key==="Hosts"){
|
|
||||||
series.values = series.values.map(function(d) {
|
|
||||||
return {
|
|
||||||
x: d[0],
|
|
||||||
y: d[1]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if(series.key==="License"){
|
|
||||||
series.values = series.values.map(function(d) {
|
|
||||||
return {
|
|
||||||
x: d[0],
|
|
||||||
y: license
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
return series;
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
nv.addGraph({
|
|
||||||
generate: function() {
|
|
||||||
var width = $('.graph-container').width(), // nv.utils.windowSize().width/3,
|
|
||||||
height = $('.graph-container').height()*0.6; //nv.utils.windowSize().height/5,
|
|
||||||
license_graph = nv.models.lineChart()
|
|
||||||
.margin({top: 15, right: 75, bottom: 40, left: 85})
|
|
||||||
.x(function(d,i) { return i ;})
|
|
||||||
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
|
|
||||||
.transitionDuration(350) //how fast do you want the lines to transition?
|
|
||||||
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
|
|
||||||
.showYAxis(true) //Show the y-axis
|
|
||||||
.showXAxis(true) //Show the x-axis
|
|
||||||
;
|
|
||||||
|
|
||||||
license_graph.xAxis
|
|
||||||
.axisLabel("Time")
|
|
||||||
.tickFormat(function(d) {
|
|
||||||
var dx = graphData[0].values[d] && graphData[0].values[d].x || 0;
|
|
||||||
return dx ? d3.time.format('%m/%d')(new Date(Number(dx+'000'))) : '';
|
|
||||||
});
|
|
||||||
|
|
||||||
license_graph.yAxis //Chart y-axis settings
|
|
||||||
.axisLabel('Hosts')
|
|
||||||
.tickFormat(d3.format('.f'));
|
|
||||||
|
|
||||||
d3.select('.host-count-graph svg')
|
|
||||||
.datum(graphData).transition()
|
|
||||||
.attr('width', width)
|
|
||||||
.attr('height', height)
|
|
||||||
.duration(500)
|
|
||||||
.call(license_graph)
|
|
||||||
.style({
|
|
||||||
// 'width': width,
|
|
||||||
// 'height': height,
|
|
||||||
"font-family": 'Open Sans',
|
|
||||||
"font-style": "normal",
|
|
||||||
"font-weight":400,
|
|
||||||
"src": "url(/static/fonts/OpenSans-Regular.ttf)"
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
// nv.utils.windowResize(license_graph.update);
|
|
||||||
scope.$emit('WidgetLoaded');
|
|
||||||
return license_graph;
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
//});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
@ -1,128 +0,0 @@
|
|||||||
/*********************************************
|
|
||||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name widgets.function:HostPieChart
|
|
||||||
* @description
|
|
||||||
* HostPieChart.js
|
|
||||||
*
|
|
||||||
* file for the host status pie chart
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
angular.module('HostPieChartWidget', ['RestServices', 'Utilities'])
|
|
||||||
.factory('HostPieChart', ['$rootScope', '$compile',
|
|
||||||
//'Rest', 'GetBasePath', 'ProcessErrors', 'Wait',
|
|
||||||
function ($rootScope, $compile){
|
|
||||||
//, Rest, GetBasePath, ProcessErrors) {
|
|
||||||
return function (params) {
|
|
||||||
|
|
||||||
var scope = params.scope,
|
|
||||||
target = params.target,
|
|
||||||
dashboard = params.dashboard,
|
|
||||||
html, element, data,
|
|
||||||
canvas, context, winHeight, available_height, host_pie_chart;
|
|
||||||
|
|
||||||
// html = "<div class=\"graph-container\">\n";
|
|
||||||
|
|
||||||
html ="<div class=\"row\">\n";
|
|
||||||
html += "<div id=\"job-status-title\" class=\"h6 col-xs-8 text-center\"><b>Host Status</b></div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
html +="<div class=\"row\">\n";
|
|
||||||
html += "<div class=\"host-pie-chart text-center\"><svg></svg></div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
// html += "</div>\n";
|
|
||||||
|
|
||||||
element = angular.element(document.getElementById(target));
|
|
||||||
element.html(html);
|
|
||||||
$compile(element)(scope);
|
|
||||||
|
|
||||||
if (scope.removeResizeHostPieGraph) {
|
|
||||||
scope.removeResizeHostPieGraph();
|
|
||||||
}
|
|
||||||
scope.removeResizeHostPieGraph= scope.$on('ResizeHostPieGraph', function () {
|
|
||||||
if($(window).width()<500){
|
|
||||||
$('.graph-container').height(300);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
var winHeight = $(window).height(),
|
|
||||||
available_height = winHeight - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120;
|
|
||||||
$('.graph-container').height(available_height/2);
|
|
||||||
if(host_pie_chart){
|
|
||||||
host_pie_chart.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(dashboard.hosts.total+dashboard.hosts.failed>0){
|
|
||||||
data = [
|
|
||||||
{
|
|
||||||
"label": "Successful",
|
|
||||||
"color": "#60D66F",
|
|
||||||
"value" : dashboard.hosts.total
|
|
||||||
} ,
|
|
||||||
{
|
|
||||||
"label": "Failed",
|
|
||||||
"color" : "#ff5850",
|
|
||||||
"value" : dashboard.hosts.failed
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
nv.addGraph(function() {
|
|
||||||
var width = $('.graph-container').width(), // nv.utils.windowSize().width/3,
|
|
||||||
height = $('.graph-container').height()*0.7; //nv.utils.windowSize().height/5,
|
|
||||||
host_pie_chart = nv.models.pieChart()
|
|
||||||
.margin({top: 5, right: 75, bottom: 40, left: 85})
|
|
||||||
.x(function(d) { return d.label; })
|
|
||||||
.y(function(d) { return d.value; })
|
|
||||||
.showLabels(true)
|
|
||||||
.labelThreshold(0.01)
|
|
||||||
.tooltipContent(function(x, y) {
|
|
||||||
return '<b>'+x+'</b>'+ '<p>' + Math.floor(y.replace(',','')) + ' Hosts ' + '</p>';
|
|
||||||
})
|
|
||||||
.color(['#60D66F', '#ff5850']);
|
|
||||||
|
|
||||||
host_pie_chart.pie.pieLabelsOutside(true).labelType("percent");
|
|
||||||
|
|
||||||
d3.select(".host-pie-chart svg")
|
|
||||||
.datum(data)
|
|
||||||
.attr('width', width)
|
|
||||||
.attr('height', height)
|
|
||||||
.transition().duration(350)
|
|
||||||
.call(host_pie_chart)
|
|
||||||
.style({
|
|
||||||
"font-family": 'Open Sans',
|
|
||||||
"font-style": "normal",
|
|
||||||
"font-weight":400,
|
|
||||||
"src": "url(/static/fonts/OpenSans-Regular.ttf)"
|
|
||||||
});
|
|
||||||
// nv.utils.windowResize(host_pie_chart.update);
|
|
||||||
scope.$emit('WidgetLoaded');
|
|
||||||
return host_pie_chart;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
winHeight = $(window).height();
|
|
||||||
available_height = winHeight - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120;
|
|
||||||
$('.graph-container:eq(1)').height(available_height/2);
|
|
||||||
$('.host-pie-chart svg').replaceWith('<canvas id="circlecanvas" width="120" height="120"></canvas>');
|
|
||||||
|
|
||||||
canvas = document.getElementById("circlecanvas");
|
|
||||||
context = canvas.getContext("2d");
|
|
||||||
context.arc(55, 55, 50, 0, Math.PI * 2, false);
|
|
||||||
context.lineWidth = 1;
|
|
||||||
context.strokeStyle = '#1778c3';
|
|
||||||
context.stroke();
|
|
||||||
context.font = "12px Open Sans";
|
|
||||||
context.fillText("No Host data",18,55);
|
|
||||||
|
|
||||||
scope.$emit('WidgetLoaded');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
@ -1,219 +0,0 @@
|
|||||||
/*********************************************
|
|
||||||
* Copyright (c) 2014 AnsibleWorks, Inc.
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name widgets.function:JobStatusGraph
|
|
||||||
* @description
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
angular.module('JobStatusGraphWidget', ['RestServices', 'Utilities'])
|
|
||||||
.factory('JobStatusGraph', ['$rootScope', '$compile', '$location' , 'Rest', 'GetBasePath', 'ProcessErrors', 'Wait',
|
|
||||||
function ($rootScope, $compile , $location, Rest, GetBasePath, ProcessErrors) {
|
|
||||||
return function (params) {
|
|
||||||
|
|
||||||
var scope = params.scope,
|
|
||||||
target = params.target,
|
|
||||||
// dashboard = params.dashboard,
|
|
||||||
html, element, url, job_status_chart,
|
|
||||||
period="month",
|
|
||||||
job_type="all";
|
|
||||||
|
|
||||||
// html = "<div class=\"graph-container\">\n";
|
|
||||||
|
|
||||||
html = "<div class=\"row\">\n";
|
|
||||||
html += "<div id=\"job-status-title\" class=\"h6 col-xs-2 col-sm-3 col-lg-4 text-center\"><b>Job Status</b></div>\n"; // for All Jobs, Past Month
|
|
||||||
|
|
||||||
html += "<div class=\"h6 col-xs-5 col-sm-5 col-lg-4\">\n";
|
|
||||||
html += "<div class=\"dropdown\">\n";
|
|
||||||
html += "Job Type: <a id=\"type-dropdown\" role=\"button\" data-toggle=\"dropdown\" data-target=\"#\" href=\"/page.html\">\n";
|
|
||||||
html += "All<span class=\"caret\"></span>\n";
|
|
||||||
html += " </a>\n";
|
|
||||||
|
|
||||||
html += "<ul class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"type-dropdown\">\n";
|
|
||||||
html += "<li><a class=\"m\" id=\"all\">All</a></li>\n";
|
|
||||||
html += "<li><a class=\"m\" id=\"inv_sync\">Inventory Sync</a></li>\n";
|
|
||||||
html += "<li><a class=\"m\" id=\"scm_update\">SCM Update</a></li>\n";
|
|
||||||
html += "<li><a class=\"m\" id=\"playbook_run\">Playbook Run</a></li>\n";
|
|
||||||
html += "</ul>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
html += "</div>\n"; //end of filter div
|
|
||||||
|
|
||||||
html += "<div class=\"h6 col-xs-5 col-sm-4 col-lg-4\">\n";
|
|
||||||
html += "<div class=\"dropdown\">\n";
|
|
||||||
html += "Period: <a id=\"period-dropdown\" role=\"button\" data-toggle=\"dropdown\" data-target=\"#\" href=\"/page.html\">\n";
|
|
||||||
html += "Past Month<span class=\"caret\"></span>\n";
|
|
||||||
html += " </a>\n";
|
|
||||||
|
|
||||||
html += "<ul class=\"dropdown-menu\" role=\"menu\" aria-labelledby=\"period-dropdown\">\n";
|
|
||||||
html += "<li><a class=\"n\" id=\"day\" >Past 24 Hours </a></li>\n";
|
|
||||||
html += "<li><a class=\"n\" id=\"week\">Past Week</a></li>\n";
|
|
||||||
html += "<li><a class=\"n\" id=\"month\">Past Month</a></li>\n";
|
|
||||||
html += "</ul>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
html += "</div>\n"; //end of filter div
|
|
||||||
|
|
||||||
html += "</div>\n"; // end of row
|
|
||||||
|
|
||||||
html +="<div class=\"row\">\n";
|
|
||||||
html += "<div class=\"job-status-graph\"><svg></svg></div>\n";
|
|
||||||
html += "</div>\n";
|
|
||||||
|
|
||||||
// html += "</div>\n";
|
|
||||||
|
|
||||||
function createGraph(){
|
|
||||||
|
|
||||||
url = GetBasePath('dashboard')+'graphs/jobs/?period='+period+'&job_type='+job_type;
|
|
||||||
Rest.setUrl(url);
|
|
||||||
Rest.get()
|
|
||||||
.success(function (data){
|
|
||||||
scope.$emit('graphDataReady', data);
|
|
||||||
return job_type, period;
|
|
||||||
|
|
||||||
})
|
|
||||||
.error(function (data, status) {
|
|
||||||
ProcessErrors(scope, data, status, null, { hdr: 'Error!',
|
|
||||||
msg: 'Failed to get: ' + url + ' GET returned: ' + status });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($rootScope.removeReloadJobStatusGraph) {
|
|
||||||
$rootScope.removeReloadJobStatusGraph();
|
|
||||||
}
|
|
||||||
$rootScope.removeReloadJobStatusGraph = $rootScope.$on('ReloadJobStatusGraph', function() {
|
|
||||||
createGraph();
|
|
||||||
});
|
|
||||||
|
|
||||||
element = angular.element(document.getElementById(target));
|
|
||||||
element.html(html);
|
|
||||||
$compile(element)(scope);
|
|
||||||
|
|
||||||
createGraph();
|
|
||||||
|
|
||||||
if (scope.removeResizeJobGraph) {
|
|
||||||
scope.removeResizeJobGraph();
|
|
||||||
}
|
|
||||||
scope.removeResizeJobGraph= scope.$on('ResizeJobGraph', function () {
|
|
||||||
if($(window).width()<500){
|
|
||||||
$('.graph-container').height(300);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
var winHeight = $(window).height(),
|
|
||||||
available_height = winHeight - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120;
|
|
||||||
$('.graph-container').height(available_height/2);
|
|
||||||
job_status_chart.update();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (scope.removeGraphDataReady) {
|
|
||||||
scope.removeGraphDataReady();
|
|
||||||
}
|
|
||||||
scope.removeGraphDataReady = scope.$on('graphDataReady', function (e, data) {
|
|
||||||
|
|
||||||
|
|
||||||
var timeFormat, graphData = [
|
|
||||||
{
|
|
||||||
"color": "#60D66F",
|
|
||||||
"key": "Successful",
|
|
||||||
"values": data.jobs.successful
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key" : "Failed" ,
|
|
||||||
"color" : "#ff5850",
|
|
||||||
"values": data.jobs.failed
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
if(period==="day"){
|
|
||||||
timeFormat="%H:%M";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
timeFormat = '%m/%d';
|
|
||||||
}
|
|
||||||
graphData.map(function(series) {
|
|
||||||
series.values = series.values.map(function(d) {
|
|
||||||
return {
|
|
||||||
x: d[0],
|
|
||||||
y: d[1]
|
|
||||||
};
|
|
||||||
});
|
|
||||||
return series;
|
|
||||||
});
|
|
||||||
|
|
||||||
nv.addGraph({
|
|
||||||
generate: function() {
|
|
||||||
var width = $('.graph-container').width(), // nv.utils.windowSize().width/3,
|
|
||||||
height = $('.graph-container').height()*0.7; //nv.utils.windowSize().height/5,
|
|
||||||
job_status_chart = nv.models.lineChart()
|
|
||||||
.margin({top: 5, right: 75, bottom: 80, left: 85}) //Adjust chart margins to give the x-axis some breathing room.
|
|
||||||
.x(function(d,i) { return i; })
|
|
||||||
.useInteractiveGuideline(true) //We want nice looking tooltips and a guideline!
|
|
||||||
.transitionDuration(350) //how fast do you want the lines to transition?
|
|
||||||
.showLegend(true) //Show the legend, allowing users to turn on/off line series.
|
|
||||||
.showYAxis(true) //Show the y-axis
|
|
||||||
.showXAxis(true) //Show the x-axis
|
|
||||||
// .width(width)
|
|
||||||
// .height(height)
|
|
||||||
;
|
|
||||||
|
|
||||||
job_status_chart.xAxis
|
|
||||||
.axisLabel("Time")//.showMaxMin(true)
|
|
||||||
.tickFormat(function(d) {
|
|
||||||
var dx = graphData[0].values[d] && graphData[0].values[d].x || 0;
|
|
||||||
return dx ? d3.time.format(timeFormat)(new Date(Number(dx+'000'))) : '';
|
|
||||||
});
|
|
||||||
|
|
||||||
job_status_chart.yAxis //Chart y-axis settings
|
|
||||||
.axisLabel('Jobs')
|
|
||||||
.tickFormat(d3.format('.f'));
|
|
||||||
|
|
||||||
d3.select('.job-status-graph svg')
|
|
||||||
.datum(graphData).transition()
|
|
||||||
.attr('width', width)
|
|
||||||
.attr('height', height)
|
|
||||||
.duration(1000)
|
|
||||||
.call(job_status_chart)
|
|
||||||
.style({
|
|
||||||
// 'width': width,
|
|
||||||
// 'height': height,
|
|
||||||
"font-family": 'Open Sans',
|
|
||||||
"font-style": "normal",
|
|
||||||
"font-weight":400,
|
|
||||||
"src": "url(/static/fonts/OpenSans-Regular.ttf)"
|
|
||||||
});
|
|
||||||
|
|
||||||
// when the Period drop down filter is used, create a new graph based on the
|
|
||||||
d3.selectAll(".n")
|
|
||||||
.on("click", function() {
|
|
||||||
period = this.getAttribute("id");
|
|
||||||
$('#period-dropdown').replaceWith("<a id=\"period-dropdown\" role=\"button\" data-toggle=\"dropdown\" data-target=\"#\" href=\"/page.html\">"+this.text+"<span class=\"caret\"><span>\n");
|
|
||||||
|
|
||||||
createGraph();
|
|
||||||
});
|
|
||||||
|
|
||||||
//On click, update with new data
|
|
||||||
d3.selectAll(".m")
|
|
||||||
.on("click", function() {
|
|
||||||
job_type = this.getAttribute("id");
|
|
||||||
$('#type-dropdown').replaceWith("<a id=\"type-dropdown\" role=\"button\" data-toggle=\"dropdown\" data-target=\"#\" href=\"/page.html\">"+this.text+"<span class=\"caret\"><span>\n");
|
|
||||||
|
|
||||||
createGraph();
|
|
||||||
});
|
|
||||||
|
|
||||||
scope.$emit('WidgetLoaded');
|
|
||||||
return job_status_chart;
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
@ -1964,3 +1964,15 @@ tr td button i {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nvtooltip {
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nvtooltip td.value {
|
||||||
|
padding-right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nvd3 g.nv-groups path.nv-line {
|
||||||
|
stroke-width: 3px;
|
||||||
|
}
|
||||||
|
|||||||
@ -30,4 +30,4 @@
|
|||||||
"_source": "git://github.com/sdecima/javascript-detect-element-resize.git",
|
"_source": "git://github.com/sdecima/javascript-detect-element-resize.git",
|
||||||
"_target": "~0.5.3",
|
"_target": "~0.5.3",
|
||||||
"_originalSource": "javascript-detect-element-resize"
|
"_originalSource": "javascript-detect-element-resize"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,9 +10,9 @@
|
|||||||
(function ( $ ) {
|
(function ( $ ) {
|
||||||
var attachEvent = document.attachEvent,
|
var attachEvent = document.attachEvent,
|
||||||
stylesCreated = false;
|
stylesCreated = false;
|
||||||
|
|
||||||
var jQuery_resize = $.fn.resize;
|
var jQuery_resize = $.fn.resize;
|
||||||
|
|
||||||
$.fn.resize = function(callback) {
|
$.fn.resize = function(callback) {
|
||||||
return this.each(function() {
|
return this.each(function() {
|
||||||
if(this == window)
|
if(this == window)
|
||||||
@ -27,14 +27,14 @@
|
|||||||
removeResizeListener(this, callback);
|
removeResizeListener(this, callback);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!attachEvent) {
|
if (!attachEvent) {
|
||||||
var requestFrame = (function(){
|
var requestFrame = (function(){
|
||||||
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
|
var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
|
||||||
function(fn){ return window.setTimeout(fn, 20); };
|
function(fn){ return window.setTimeout(fn, 20); };
|
||||||
return function(fn){ return raf(fn); };
|
return function(fn){ return raf(fn); };
|
||||||
})();
|
})();
|
||||||
|
|
||||||
var cancelFrame = (function(){
|
var cancelFrame = (function(){
|
||||||
var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
|
var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
|
||||||
window.clearTimeout;
|
window.clearTimeout;
|
||||||
@ -58,7 +58,7 @@
|
|||||||
return element.offsetWidth != element.__resizeLast__.width ||
|
return element.offsetWidth != element.__resizeLast__.width ||
|
||||||
element.offsetHeight != element.__resizeLast__.height;
|
element.offsetHeight != element.__resizeLast__.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollListener(e){
|
function scrollListener(e){
|
||||||
var element = this;
|
var element = this;
|
||||||
resetTriggers(this);
|
resetTriggers(this);
|
||||||
@ -73,7 +73,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Detect CSS Animations support to detect element display/re-attach */
|
/* Detect CSS Animations support to detect element display/re-attach */
|
||||||
var animation = false,
|
var animation = false,
|
||||||
animationstring = 'animation',
|
animationstring = 'animation',
|
||||||
@ -84,8 +84,8 @@
|
|||||||
pfx = '';
|
pfx = '';
|
||||||
{
|
{
|
||||||
var elm = document.createElement('fakeelement');
|
var elm = document.createElement('fakeelement');
|
||||||
if( elm.style.animationName !== undefined ) { animation = true; }
|
if( elm.style.animationName !== undefined ) { animation = true; }
|
||||||
|
|
||||||
if( animation === false ) {
|
if( animation === false ) {
|
||||||
for( var i = 0; i < domPrefixes.length; i++ ) {
|
for( var i = 0; i < domPrefixes.length; i++ ) {
|
||||||
if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
|
if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
|
||||||
@ -99,12 +99,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var animationName = 'resizeanim';
|
var animationName = 'resizeanim';
|
||||||
var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
|
var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
|
||||||
var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
|
var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStyles() {
|
function createStyles() {
|
||||||
if (!stylesCreated) {
|
if (!stylesCreated) {
|
||||||
//opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
|
//opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
|
||||||
@ -113,7 +113,7 @@
|
|||||||
'.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
|
'.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
|
||||||
head = document.head || document.getElementsByTagName('head')[0],
|
head = document.head || document.getElementsByTagName('head')[0],
|
||||||
style = document.createElement('style');
|
style = document.createElement('style');
|
||||||
|
|
||||||
style.type = 'text/css';
|
style.type = 'text/css';
|
||||||
if (style.styleSheet) {
|
if (style.styleSheet) {
|
||||||
style.styleSheet.cssText = css;
|
style.styleSheet.cssText = css;
|
||||||
@ -125,7 +125,7 @@
|
|||||||
stylesCreated = true;
|
stylesCreated = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addResizeListener = function(element, fn){
|
window.addResizeListener = function(element, fn){
|
||||||
if (attachEvent) element.attachEvent('onresize', fn);
|
if (attachEvent) element.attachEvent('onresize', fn);
|
||||||
else {
|
else {
|
||||||
@ -140,7 +140,7 @@
|
|||||||
element.appendChild(element.__resizeTriggers__);
|
element.appendChild(element.__resizeTriggers__);
|
||||||
resetTriggers(element);
|
resetTriggers(element);
|
||||||
element.addEventListener('scroll', scrollListener, true);
|
element.addEventListener('scroll', scrollListener, true);
|
||||||
|
|
||||||
/* Listen for a css animation to detect element display/re-attach */
|
/* Listen for a css animation to detect element display/re-attach */
|
||||||
animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
|
animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
|
||||||
if(e.animationName == animationName)
|
if(e.animationName == animationName)
|
||||||
@ -150,7 +150,7 @@
|
|||||||
element.__resizeListeners__.push(fn);
|
element.__resizeListeners__.push(fn);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.removeResizeListener = function(element, fn){
|
window.removeResizeListener = function(element, fn){
|
||||||
if (attachEvent) element.detachEvent('onresize', fn);
|
if (attachEvent) element.detachEvent('onresize', fn);
|
||||||
else {
|
else {
|
||||||
@ -161,4 +161,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}( jQuery ));
|
}( jQuery ));
|
||||||
|
|||||||
@ -11354,4 +11354,4 @@ nv.models.stackedAreaChart = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
nv.version = "1.7.1";
|
nv.version = "1.7.1";
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -1,58 +1,35 @@
|
|||||||
|
|
||||||
<div class="tab-pane" id="home">
|
<div class="tab-pane" id="home">
|
||||||
<div ng-cloak id="htmlTemplate" style="padding:10px">
|
<div ng-cloak id="htmlTemplate" style="padding:10px">
|
||||||
<div id="refresh-row" class="row">
|
<div id="refresh-row" class="row">
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<div id="home-list-actions" class="list-actions pull-right">
|
<div id="home-list-actions" class="list-actions pull-right">
|
||||||
<button
|
<button
|
||||||
toolbar-button
|
toolbar-button
|
||||||
mode="all"
|
mode="all"
|
||||||
aw-tool-tip="Refresh the page"
|
aw-tool-tip="Refresh the page"
|
||||||
ng-click="refresh()"
|
ng-click="refresh()"
|
||||||
ng-show="socketStatus == 'error'"
|
ng-show="socketStatus == 'error'"
|
||||||
icon-name="refresh"
|
icon-name="refresh"
|
||||||
toolbar="true">
|
toolbar="true">
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
toolbar-button
|
toolbar-button
|
||||||
mode="all"
|
mode="all"
|
||||||
ng-click="showActivity()"
|
ng-click="showActivity()"
|
||||||
aw-tool-tip="View Activity Stream"
|
aw-tool-tip="View Activity Stream"
|
||||||
icon-name="stream"
|
icon-name="stream"
|
||||||
toolbar="true"
|
toolbar="true"
|
||||||
aw-feature="activity_streams">
|
aw-feature="activity_streams">
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
<!-- <button type="button" class="btn btn-xs btn-primary ng-hide" ng-click="refreshJobs()" id="refresh_btn" aw-tool-tip="Refresh the page" data-placement="top" ng-show="socketStatus == 'error'" data-original-title="" title=""><i class="fa fa-refresh fa-lg"></i> </button></div> -->
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div id="dash-counts" class="col-sm-12 col-xs-12"></div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div class="left-side col-lg-6 col-md-12">
|
|
||||||
<div id="dash-job-status-graph" auto-size-module class="graph-container">
|
|
||||||
<job-status-graph data="graphData.jobStatus" period="month" job-type="all"></job-status-graph>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="right-side col-lg-6 col-md-12">
|
|
||||||
<div id="dash-host-status-graph" auto-size-module class="graph-container">
|
|
||||||
<host-status-graph data="dashboardData"></host-status-graph>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row">
|
|
||||||
<div id="dash-jobs-list" class="left-side col-lg-6 col-md-12"></div>
|
|
||||||
<div class="right-side col-lg-6 col-md-12">
|
|
||||||
<div id="dash-host-count-graph" auto-size-module class="graph-container">
|
|
||||||
<host-count-graph ng-if="user_is_superuser" data="graphData.hostCounts"></host-count-graph>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div ng-include="'/static/partials/schedule_dialog.html'"></div>
|
<dashboard></dashboard>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<!-- <div ng-include="'/static/partials/schedule_dialog.html'"></div>
|
||||||
<div ng-include="'/static/partials/logviewer.html'"></div>
|
<div ng-include="'/static/partials/logviewer.html'"></div>
|
||||||
<div id="host-modal-dialog" style="display: none;" class="dialog-content"></div>
|
<div id="host-modal-dialog" style="display: none;" class="dialog-content"></div> -->
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
<div class="graph-wrapper">
|
|
||||||
<div class="clearfix toolbar">
|
|
||||||
<div class="h6 pull-left">
|
|
||||||
<b>Host Count</b>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="graph">
|
|
||||||
<svg width="100%" height="100%"></svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
<div class="graph-wrapper">
|
|
||||||
<div class="clearfix toolbar">
|
|
||||||
<div id="job-status-title" class="h6 pull-left">
|
|
||||||
<b>Host Status</b>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="graph">
|
|
||||||
<svg width="100%" height="100%" preserveAspectRatio="xMinYMin"></svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@ -1,39 +0,0 @@
|
|||||||
<div class="graph-wrapper job-status-graph">
|
|
||||||
<div class="clearfix toolbar">
|
|
||||||
<div id="job-status-title" class="h6 pull-left">
|
|
||||||
<b>Job Status</b>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h6 dropdown pull-right">
|
|
||||||
Period: <a id="period-dropdown" role="button" data-toggle="dropdown" data-target="#" href="/page.html">
|
|
||||||
Past Month<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<ul class="dropdown-menu" role="menu" aria-labelledby="period-dropdown">
|
|
||||||
<li><a class="n" id="day" >Past 24 Hours </a></li>
|
|
||||||
<li><a class="n" id="week">Past Week</a></li>
|
|
||||||
<li><a class="n" id="month">Past Month</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="h6 dropdown pull-right" style="padding-right: .5em;">
|
|
||||||
Job Type: <a id="type-dropdown" role="button" data-toggle="dropdown" data-target="#" href="/page.html">
|
|
||||||
All<span class="caret"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<ul class="dropdown-menu" role="menu" aria-labelledby="type-dropdown">
|
|
||||||
<li><a class="m" id="all">All</a></li>
|
|
||||||
<li><a class="m" id="inv_sync">Inventory Sync</a></li>
|
|
||||||
<li><a class="m" id="scm_update">SCM Update</a></li>
|
|
||||||
<li><a class="m" id="playbook_run">Playbook Run</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="graph">
|
|
||||||
<svg width="100%" height="100%"></svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@ -1,12 +1,17 @@
|
|||||||
Alias /munin /var/www/html/munin/
|
|
||||||
<Directory /var/www/html/munin/>
|
Alias /munin /var/cache/munin/www
|
||||||
|
<Directory /var/cache/munin/www>
|
||||||
Order Allow,Deny
|
Order Allow,Deny
|
||||||
Allow from all
|
Allow from all
|
||||||
|
Options FollowSymLinks
|
||||||
|
|
||||||
AuthUserFile /var/lib/awx/.munin_htpasswd
|
AuthUserFile /var/lib/awx/.munin_htpasswd
|
||||||
AuthName "Munin"
|
AuthName "Munin"
|
||||||
AuthType Basic
|
AuthType Basic
|
||||||
require valid-user
|
require valid-user
|
||||||
|
|
||||||
|
<IfModule mod_expires.c>
|
||||||
|
ExpiresActive On
|
||||||
|
ExpiresDefault M310
|
||||||
|
</IfModule>
|
||||||
</Directory>
|
</Directory>
|
||||||
ScriptAlias /munin-cgi/munin-cgi-graph /var/www/cgi-bin/munin-cgi-graph
|
|
||||||
Loading…
x
Reference in New Issue
Block a user