diff --git a/awx/ui/static/ansible-bootstrap/dropdowns.less b/awx/ui/static/ansible-bootstrap/dropdowns.less index f165165e7a..ba4acf069a 100644 --- a/awx/ui/static/ansible-bootstrap/dropdowns.less +++ b/awx/ui/static/ansible-bootstrap/dropdowns.less @@ -210,4 +210,3 @@ } } } - diff --git a/awx/ui/static/js/app.js b/awx/ui/static/js/app.js index b7848c93cc..64e684fa11 100644 --- a/awx/ui/static/js/app.js +++ b/awx/ui/static/js/app.js @@ -29,11 +29,7 @@ import {Authenticate} from 'tower/controllers/Authentication'; import {CredentialsAdd, CredentialsEdit, CredentialsList} from 'tower/controllers/Credentials'; import {JobsListController} from 'tower/controllers/Jobs'; 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 routeExtensions from 'tower/shared/route-extensions/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 mainMenu from 'tower/main-menu/main'; import browserData from 'tower/browser-data/main'; +import dashboard from 'tower/dashboard/main'; import {JobDetailController} from 'tower/controllers/JobDetail'; import {JobStdoutController} from 'tower/controllers/JobStdout'; @@ -79,14 +76,13 @@ var tower = angular.module('Tower', [ 'ngSanitize', 'ngCookies', 'RestServices', - dataServices.name, - dashboardGraphs.name, routeExtensions.name, browserData.name, breadcrumbs.name, systemTracking.name, setupMenu.name, mainMenu.name, + dashboard.name, 'AuthService', 'Utilities', 'LicenseHelper', @@ -149,8 +145,6 @@ var tower = angular.module('Tower', [ 'AccessHelper', 'SelectionHelper', 'HostGroupsFormDefinition', - 'DashboardCountsWidget', - 'DashboardJobsWidget', 'PortalJobsWidget', 'StreamWidget', 'JobsHelper', @@ -863,10 +857,9 @@ var tower = angular.module('Tower', [ templateUrl: urlPrefix + 'partials/home.html', controller: Home, resolve: { - graphData: ['$q', 'jobStatusGraphData', 'hostCountGraphData', 'FeaturesService', function($q, jobStatusGraphData, hostCountGraphData, FeaturesService) { + graphData: ['$q', 'jobStatusGraphData', 'FeaturesService', function($q, jobStatusGraphData, FeaturesService) { return $q.all({ jobStatus: jobStatusGraphData.get("month", "all"), - hostCounts: hostCountGraphData.get(), features: FeaturesService.get() }); }] diff --git a/awx/ui/static/js/controllers/Home.js b/awx/ui/static/js/controllers/Home.js index 00664fc466..5ed11aa665 100644 --- a/awx/ui/static/js/controllers/Home.js +++ b/awx/ui/static/js/controllers/Home.js @@ -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('home'); - var borderStyles; + var dataCount = 0; - if (!$routeParams.login) { - // If we're not logging in, start the Wait widget. Otherwise, it's already running. - //Wait('start'); + if ($scope.removeDashboardDataLoadComplete) { + $scope.removeDashboardDataLoadComplete(); } + $scope.removeDashboardDataLoadComplete = $scope.$on('dashboardDataLoadComplete', function () { + dataCount++; + if (dataCount === 3) { + Wait("stop"); + dataCount = 0; + } + }); if ($scope.removeDashboardReady) { $scope.removeDashboardReady(); } $scope.removeDashboardReady = $scope.$on('dashboardReady', function (e, 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.dashboardCountsData = data; $scope.graphData = graphData; + $scope.$emit('dashboardDataLoadComplete'); var cleanupJobListener = $rootScope.$on('DataReceived:JobStatusGraph', function(e, data) { @@ -70,16 +60,25 @@ export function Home($scope, $compile, $routeParams, $rootScope, $location, $log $scope.$on('$destroy', function() { 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 () { Stream({ scope: $scope @@ -97,13 +96,30 @@ export function Home($scope, $compile, $routeParams, $rootScope, $location, $log .error(function (data, 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(); - } -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' ]; diff --git a/awx/ui/static/js/dashboard/counts/dashboard-counts.block.less b/awx/ui/static/js/dashboard/counts/dashboard-counts.block.less new file mode 100644 index 0000000000..4905af1dbc --- /dev/null +++ b/awx/ui/static/js/dashboard/counts/dashboard-counts.block.less @@ -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; +} diff --git a/awx/ui/static/js/dashboard/counts/dashboard-counts.directive.js b/awx/ui/static/js/dashboard/counts/dashboard-counts.directive.js new file mode 100644 index 0000000000..ac0f201237 --- /dev/null +++ b/awx/ui/static/js/dashboard/counts/dashboard-counts.directive.js @@ -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); }); + } + } + }; + } + ]; diff --git a/awx/ui/static/js/dashboard/counts/dashboard-counts.partial.html b/awx/ui/static/js/dashboard/counts/dashboard-counts.partial.html new file mode 100644 index 0000000000..522b4fff4d --- /dev/null +++ b/awx/ui/static/js/dashboard/counts/dashboard-counts.partial.html @@ -0,0 +1,10 @@ +
+ +
+ {{ count.number }} +
+
{{ count.label }}
+
+
diff --git a/awx/ui/static/js/dashboard/counts/main.js b/awx/ui/static/js/dashboard/counts/main.js new file mode 100644 index 0000000000..0c069d9588 --- /dev/null +++ b/awx/ui/static/js/dashboard/counts/main.js @@ -0,0 +1,5 @@ +import dashboardCountsDirective from 'tower/dashboard/counts/dashboard-counts.directive'; + +export default + angular.module('DashboardCountModules', []) + .directive('dashboardCounts', dashboardCountsDirective); diff --git a/awx/ui/static/js/dashboard/dashboard.block.less b/awx/ui/static/js/dashboard/dashboard.block.less new file mode 100644 index 0000000000..e7b77e5fb4 --- /dev/null +++ b/awx/ui/static/js/dashboard/dashboard.block.less @@ -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%; + } +} diff --git a/awx/ui/static/js/dashboard/dashboard.directive.js b/awx/ui/static/js/dashboard/dashboard.directive.js new file mode 100644 index 0000000000..c330aeb137 --- /dev/null +++ b/awx/ui/static/js/dashboard/dashboard.directive.js @@ -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) { + } + }; + } + ]; diff --git a/awx/ui/static/js/dashboard/dashboard.partial.html b/awx/ui/static/js/dashboard/dashboard.partial.html new file mode 100644 index 0000000000..dc2aa78245 --- /dev/null +++ b/awx/ui/static/js/dashboard/dashboard.partial.html @@ -0,0 +1,11 @@ +
+ + + + + + +
diff --git a/awx/ui/static/js/dashboard/graphs/dashboard-graphs.block.less b/awx/ui/static/js/dashboard/graphs/dashboard-graphs.block.less new file mode 100644 index 0000000000..e4167e5ed1 --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/dashboard-graphs.block.less @@ -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; +} diff --git a/awx/ui/static/js/dashboard/graphs/dashboard-graphs.directive.js b/awx/ui/static/js/dashboard/graphs/dashboard-graphs.directive.js new file mode 100644 index 0000000000..b27418a94c --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/dashboard-graphs.directive.js @@ -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"); + } + }; + } + ]; diff --git a/awx/ui/static/js/dashboard/graphs/dashboard-graphs.partial.html b/awx/ui/static/js/dashboard/graphs/dashboard-graphs.partial.html new file mode 100644 index 0000000000..5c69410f15 --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/dashboard-graphs.partial.html @@ -0,0 +1,32 @@ +
+
+
+ Job Status +
+
+ Host Status +
+
+
+
+ + +
+
+ + +
+
+
diff --git a/awx/ui/static/js/services/adjust-graph-size.js b/awx/ui/static/js/dashboard/graphs/graph-helpers/adjust-graph-size.service.js similarity index 70% rename from awx/ui/static/js/services/adjust-graph-size.js rename to awx/ui/static/js/dashboard/graphs/graph-helpers/adjust-graph-size.service.js index 51777c9521..97d6803219 100644 --- a/awx/ui/static/js/services/adjust-graph-size.js +++ b/awx/ui/static/js/dashboard/graphs/graph-helpers/adjust-graph-size.service.js @@ -53,37 +53,35 @@ export default function() { // Calling chartModel.update() at the end instructs nv to process our changes. // return function adjustGraphSize(chartModel, element) { - var parentHeight = element.parent().parent().height(); - var toolbarHeight = element.find('.toolbar').height(); - var container = element.find('svg').parent(); - var margins = chartModel.margin(); + if (chartModel) { + var margins = chartModel.margin(); + var graph = d3.select(element.find('svg')[0]); + 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]); - var width = parseInt(graph.style('width')) - margins.left - margins.right; - var height = parseInt(graph.style('height')) - margins.top - margins.bottom; + if (height < 160) { + graph.select('.y.nv-axis').select('.domain').style('display', 'none'); + graph.select('.y.nv-axis').select('.domain').style('display', 'initial'); + } - chartModel.xRange([0, width]); - chartModel.yRange([height, 0]); + graph.select('.x.nv-axis') + .attr('transform', 'translate(0, ' + height + ')') + .call(chartModel.xAxis); - chartModel.xAxis.ticks(Math.max(width / 75, 2)); - chartModel.yAxis.ticks(Math.max(height / 50, 2)); + graph.selectAll('.line') + .attr('d', chartModel.lines); - if (height < 160) { - graph.select('.y.nv-axis').select('.domain').style('display', 'none'); - graph.select('.y.nv-axis').select('.domain').style('display', 'initial'); + if (chartModel.update) { + chartModel.update(); + } } - - graph.select('.x.nv-axis') - .attr('transform', 'translate(0, ' + height + ')') - .call(chartModel.xAxis); - - graph.selectAll('.line') - .attr('d', chartModel.lines); - - chartModel.update(); }; } diff --git a/awx/ui/static/js/directives/auto-size-module.js b/awx/ui/static/js/dashboard/graphs/graph-helpers/auto-size.directive.js similarity index 63% rename from awx/ui/static/js/directives/auto-size-module.js rename to awx/ui/static/js/dashboard/graphs/graph-helpers/auto-size.directive.js index 3c63914a94..fa7e7424bc 100644 --- a/awx/ui/static/js/directives/auto-size-module.js +++ b/awx/ui/static/js/dashboard/graphs/graph-helpers/auto-size.directive.js @@ -9,16 +9,18 @@ function AutoSizeModule($window) { // fit into a single a page; assumes there are 2 rows // of modules, with the available height being offset // by the navbar & the count summaries module - return function(scope, element) { - - function adjustSizeInitially() { - adjustSize(); - } + return function(scope, element, attrs) { function adjustSize() { - var winHeight = $($window).height(), - available_height = winHeight - $('#main-menu-container .navbar').outerHeight() - $('#count-container').outerHeight() - 120; - element.height(available_height/2); + if (attrs.graphType === "hostStatus") { + if (element.parent().width() > 596) { + element.height(596); + } else { + element.height(element.parent().width()); + } + } else { + element.height(320); + } } $($window).resize(adjustSize); @@ -30,8 +32,8 @@ function AutoSizeModule($window) { // This makes sure count-container div is loaded // by controllers/Home.js before we use it // to determine the available window height - scope.$on('dashboardReady', function() { - adjustSizeInitially(); + scope.$on('resizeGraphs', function() { + adjustSize(); }); }; diff --git a/awx/ui/static/js/dashboard/graphs/graph-helpers/main.js b/awx/ui/static/js/dashboard/graphs/graph-helpers/main.js new file mode 100644 index 0000000000..ae8dd9174e --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/graph-helpers/main.js @@ -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); diff --git a/awx/ui/static/js/directives/host-status-graph.js b/awx/ui/static/js/dashboard/graphs/host-status/host-status-graph.directive.js similarity index 84% rename from awx/ui/static/js/directives/host-status-graph.js rename to awx/ui/static/js/dashboard/graphs/host-status/host-status-graph.directive.js index e56d3991df..1c467d2d9b 100644 --- a/awx/ui/static/js/directives/host-status-graph.js +++ b/awx/ui/static/js/dashboard/graphs/host-status/host-status-graph.directive.js @@ -1,14 +1,15 @@ export default [ '$compile', '$window', - HostStatusGraph + 'adjustGraphSize', + HostStatusGraph, ]; -function HostStatusGraph($compile, $window) { +function HostStatusGraph($compile, $window, adjustGraphSize) { return { restrict: 'E', 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) { @@ -20,12 +21,10 @@ function HostStatusGraph($compile, $window) { } }); - function adjustGraphSize() { - + function adjustHostGraphSize() { if (angular.isUndefined(host_pie_chart)) { return; } - var parentHeight = element.parent().parent().height(); var toolbarHeight = element.find('.toolbar').height(); var container = element.find('svg').parent(); @@ -38,10 +37,12 @@ function HostStatusGraph($compile, $window) { 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() { - angular.element($window).off('resize', adjustGraphSize); + angular.element($window).off('resize', adjustHostGraphSize); + $(".DashboardGraphs-graph--hostStatusGraph").removeResize(adjustHostGraphSize); }); function createGraph(data) { @@ -58,7 +59,7 @@ function HostStatusGraph($compile, $window) { ]; host_pie_chart = nv.models.pieChart() - .margin({top: 5, right: 75, bottom: 25, left: 85}) + .margin({bottom: 15}) .x(function(d) { return d.label; }) .y(function(d) { return d.value; }) .showLabels(true) @@ -101,6 +102,7 @@ function HostStatusGraph($compile, $window) { element.find('svg').replaceWith(notFoundContainer); } + } } } diff --git a/awx/ui/static/js/dashboard/graphs/host-status/host_status_graph.partial.html b/awx/ui/static/js/dashboard/graphs/host-status/host_status_graph.partial.html new file mode 100644 index 0000000000..15396d31ec --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/host-status/host_status_graph.partial.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/awx/ui/static/js/dashboard/graphs/host-status/main.js b/awx/ui/static/js/dashboard/graphs/host-status/main.js new file mode 100644 index 0000000000..b7ab1d6b3e --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/host-status/main.js @@ -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); diff --git a/awx/ui/static/js/directives/job-status-graph.js b/awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.directive.js similarity index 93% rename from awx/ui/static/js/directives/job-status-graph.js rename to awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.directive.js index f154379c84..3b5fe958c0 100644 --- a/awx/ui/static/js/directives/job-status-graph.js +++ b/awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.directive.js @@ -15,7 +15,7 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG scope: { data: '=' }, - templateUrl: '/static/partials/job_status_graph.html', + templateUrl: '/static/js/dashboard/graphs/job-status/job_status_graph.partial.html', link: link }; @@ -38,10 +38,10 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG scope.period = period; scope.jobType = jobType; }); + } function createGraph(period, jobtype, data){ - scope.period = period; scope.jobType = jobtype; @@ -73,7 +73,6 @@ function JobStatusGraph($rootScope, $compile , $location, $window, Wait, adjustG }); 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; }) .useInteractiveGuideline(true) //We want nice looking tooltips and a guideline! .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); }); + job_status_chart.legend.margin({top: 1, right:0, left:24, bottom: 0}); + adjustGraphSize(job_status_chart, element); + } function onResize() { adjustGraphSize(job_status_chart, element); + } angular.element($window).on('resize', onResize); + $(".DashboardGraphs-graph--jobStatusGraph").resize(onResize); element.on('$destroy', function() { angular.element($window).off('resize', onResize); + $(".DashboardGraphs-graph--jobStatusGraph").removeResize(onResize); }); if (scope.removeGraphDataReady) { diff --git a/awx/ui/static/js/services/job-status-graph-data.js b/awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.service.js similarity index 83% rename from awx/ui/static/js/services/job-status-graph-data.js rename to awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.service.js index 9c92eafd5d..85152f2825 100644 --- a/awx/ui/static/js/services/job-status-graph-data.js +++ b/awx/ui/static/js/dashboard/graphs/job-status/job-status-graph.service.js @@ -39,12 +39,12 @@ function JobStatusGraphData(Rest, getBasePath, processErrors, $rootScope, $q) { setupWatcher: function(period, jobType) { this.destroyWatcher = $rootScope.$on('JobStatusChange-home', function() { - getData(period, jobType).then(function(result) { - $rootScope. - $broadcast('DataReceived:JobStatusGraph', - result); - return result; - }); + getData(period, jobType).then(function(result) { + $rootScope. + $broadcast('DataReceived:JobStatusGraph', + result); + return result; + }); }); }, get: function(period, jobType) { diff --git a/awx/ui/static/js/dashboard/graphs/job-status/job_status_graph.partial.html b/awx/ui/static/js/dashboard/graphs/job-status/job_status_graph.partial.html new file mode 100644 index 0000000000..6c07f3674b --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/job-status/job_status_graph.partial.html @@ -0,0 +1,49 @@ +
+
+ Period: + + Past Month + + + +
+ +
+ Job Type: + + All + + + +
+
+ + +
+ +
diff --git a/awx/ui/static/js/dashboard/graphs/job-status/main.js b/awx/ui/static/js/dashboard/graphs/job-status/main.js new file mode 100644 index 0000000000..5758354a28 --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/job-status/main.js @@ -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); diff --git a/awx/ui/static/js/dashboard/graphs/main.js b/awx/ui/static/js/dashboard/graphs/main.js new file mode 100644 index 0000000000..9442e279c8 --- /dev/null +++ b/awx/ui/static/js/dashboard/graphs/main.js @@ -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); diff --git a/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.block.less b/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.block.less new file mode 100644 index 0000000000..b0e9bd8d52 --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.block.less @@ -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; + } +} diff --git a/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.directive.js b/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.directive.js new file mode 100644 index 0000000000..6dc6f20afb --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.directive.js @@ -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 }); + }; + } +}]; diff --git a/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.partial.html b/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.partial.html new file mode 100644 index 0000000000..dac0405a63 --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/job-templates/job-templates-list.partial.html @@ -0,0 +1,28 @@ +
+

+ Recently Used Job Templates +

+
+ +
+ + See all job templates + +
+
+

+ Recent Job Runs +

+

It doesn't seem like you have used any job templates.
+ You can create a job template here.

+
diff --git a/awx/ui/static/js/dashboard/lists/job-templates/main.js b/awx/ui/static/js/dashboard/lists/job-templates/main.js new file mode 100644 index 0000000000..abf26b9c63 --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/job-templates/main.js @@ -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); diff --git a/awx/ui/static/js/dashboard/lists/jobs/jobs-list.block.less b/awx/ui/static/js/dashboard/lists/jobs/jobs-list.block.less new file mode 100644 index 0000000000..07d744ca9c --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/jobs/jobs-list.block.less @@ -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; + } +} diff --git a/awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js b/awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js new file mode 100644 index 0000000000..0ebdc16c7a --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/jobs/jobs-list.directive.js @@ -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"); + }; + } +}]; diff --git a/awx/ui/static/js/dashboard/lists/jobs/jobs-list.partial.html b/awx/ui/static/js/dashboard/lists/jobs/jobs-list.partial.html new file mode 100644 index 0000000000..8db9ef61d9 --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/jobs/jobs-list.partial.html @@ -0,0 +1,35 @@ +
+

+ Recent Job Runs +

+
+ +
+ + See all job runs + +
+ +
+

+ Recent Job Runs +

+

It doesn't seem like you have any recent job runs.

+
diff --git a/awx/ui/static/js/dashboard/lists/jobs/main.js b/awx/ui/static/js/dashboard/lists/jobs/main.js new file mode 100644 index 0000000000..0c9e2d290d --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/jobs/main.js @@ -0,0 +1,4 @@ +import JobsListDirective from 'tower/dashboard/lists/jobs/jobs-list.directive'; + +export default angular.module('JobsList', []) + .directive('jobsList', JobsListDirective); diff --git a/awx/ui/static/js/dashboard/lists/main.js b/awx/ui/static/js/dashboard/lists/main.js new file mode 100644 index 0000000000..ff103de668 --- /dev/null +++ b/awx/ui/static/js/dashboard/lists/main.js @@ -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]); diff --git a/awx/ui/static/js/dashboard/main.js b/awx/ui/static/js/dashboard/main.js new file mode 100644 index 0000000000..85f4c5dd10 --- /dev/null +++ b/awx/ui/static/js/dashboard/main.js @@ -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); diff --git a/awx/ui/static/js/directives/_dashboard-graphs.js b/awx/ui/static/js/directives/_dashboard-graphs.js deleted file mode 100644 index ccacb29f77..0000000000 --- a/awx/ui/static/js/directives/_dashboard-graphs.js +++ /dev/null @@ -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); diff --git a/awx/ui/static/js/directives/host-count-graph.js b/awx/ui/static/js/directives/host-count-graph.js deleted file mode 100644 index b9041fd53a..0000000000 --- a/awx/ui/static/js/directives/host-count-graph.js +++ /dev/null @@ -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; - - } - } -} diff --git a/awx/ui/static/js/helpers/JobSubmission.js b/awx/ui/static/js/helpers/JobSubmission.js index 3ec4b2f8ef..0185f59ac8 100644 --- a/awx/ui/static/js/helpers/JobSubmission.js +++ b/awx/ui/static/js/helpers/JobSubmission.js @@ -744,7 +744,7 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, launch_url, html; 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/'; } else { @@ -777,7 +777,8 @@ function($compile, Rest, GetBasePath, TextareaResize,CreateDialog, GenerateForm, } scope.removePlaybookLaunchFinished = scope.$on('PlaybookLaunchFinished', function(e, data) { 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); } diff --git a/awx/ui/static/js/services/_data-services.js b/awx/ui/static/js/services/_data-services.js deleted file mode 100644 index 8f61c082c7..0000000000 --- a/awx/ui/static/js/services/_data-services.js +++ /dev/null @@ -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); diff --git a/awx/ui/static/js/services/host-count-graph-data.js b/awx/ui/static/js/services/host-count-graph-data.js deleted file mode 100644 index 5ace42cf47..0000000000 --- a/awx/ui/static/js/services/host-count-graph-data.js +++ /dev/null @@ -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); - }); - } - }; -} diff --git a/awx/ui/static/js/smart-status/smart-status.directive.js b/awx/ui/static/js/smart-status/smart-status.directive.js index f3fca643ed..73f60f7bdc 100644 --- a/awx/ui/static/js/smart-status/smart-status.directive.js +++ b/awx/ui/static/js/smart-status/smart-status.directive.js @@ -6,14 +6,15 @@ export default [ function() { }, restrict: 'E', link: function (scope, element){ - scope.formatter = function(sparklines, options, point){ var status = options.userOptions.tooltipValueLookups.status[point.offset]; //capitalize first letter - status = status.charAt(0).toUpperCase() + status.slice(1); - return "
Job ID: " + - options.userOptions.tooltipValueLookups.jobs[point.offset] + - "
Status: "+status+"
" ; + if (status) { + status = status.charAt(0).toUpperCase() + status.slice(1); + return "
Job ID: " + + options.userOptions.tooltipValueLookups.jobs[point.offset] + + "
Status: "+status+"
" ; + } }; element.sparkline(scope.sparkArray, { diff --git a/awx/ui/static/js/widgets.js b/awx/ui/static/js/widgets.js index 16d85acc5a..f173fb5c79 100644 --- a/awx/ui/static/js/widgets.js +++ b/awx/ui/static/js/widgets.js @@ -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/JobStatus"; -import "tower/widgets/JobStatusGraph"; import "tower/widgets/ObjectCount"; import "tower/widgets/PortalJobs"; import "tower/widgets/SCMSyncStatus"; import "tower/widgets/Stream"; - diff --git a/awx/ui/static/js/widgets/DashboardCounts.js b/awx/ui/static/js/widgets/DashboardCounts.js deleted file mode 100644 index cc8bcac3ee..0000000000 --- a/awx/ui/static/js/widgets/DashboardCounts.js +++ /dev/null @@ -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 = "
\n"; - - html = "
\n"; - html += "\n"; - html += "\n"; - html += "\n"; - html += "\n"; - html += "\n"; - html += "
"+dashboard.projects.failed+"
Project Sync Failures
\n"; - // html += "\n"; - html += "
\n"; - - html += "
\n"; - - - element = angular.element(document.getElementById(target)); - element.html(html); - $compile(element)(scope); - if(dashboard.hosts.failed>0 ){ - $('#failed-hosts').replaceWith(""+dashboard.hosts.failed+""); - } - if(dashboard.inventories.inventory_failed>0 ){ - $('#failed-inventories').replaceWith(""+dashboard.inventories.inventory_failed+""); - } - if(dashboard.projects.failed>0 ){ - $('#failed-projects').replaceWith(""+dashboard.projects.failed+""); - } - scope.$emit('WidgetLoaded'); - - }; - } - ]); \ No newline at end of file diff --git a/awx/ui/static/js/widgets/DashboardJobs.js b/awx/ui/static/js/widgets/DashboardJobs.js deleted file mode 100644 index 1eeb44d040..0000000000 --- a/awx/ui/static/js/widgets/DashboardJobs.js +++ /dev/null @@ -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 += "
\n"; - html += "\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; - html += "
\n"; //row - html += "
\n"; - html += "
\n"; - html += "
\n"; //list - html += "
\n"; //active-jobs-tab - html += "
\n"; - html += "
\n"; // jobs-list-container - html += "
\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); - } - - - - }; -} -]); diff --git a/awx/ui/static/js/widgets/HostGraph.js b/awx/ui/static/js/widgets/HostGraph.js deleted file mode 100644 index 58b38b7e18..0000000000 --- a/awx/ui/static/js/widgets/HostGraph.js +++ /dev/null @@ -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 = "
\n"; - html ="
\n"; - html += "
Host Count
\n"; - html += "
\n"; - html +="
\n"; - html += "
\n"; - - // html += "
\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; - - }, - - }); - //}); - }); - - - - }; - } - ]); \ No newline at end of file diff --git a/awx/ui/static/js/widgets/HostPieChart.js b/awx/ui/static/js/widgets/HostPieChart.js deleted file mode 100644 index 29625e0ea3..0000000000 --- a/awx/ui/static/js/widgets/HostPieChart.js +++ /dev/null @@ -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 = "
\n"; - - html ="
\n"; - html += "
Host Status
\n"; - html += "
\n"; - - html +="
\n"; - html += "
\n"; - html += "
\n"; - - // html += "
\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 ''+x+''+ '

' + Math.floor(y.replace(',','')) + ' Hosts ' + '

'; - }) - .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 = 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'); - } - }; - } - ]); diff --git a/awx/ui/static/js/widgets/JobStatusGraph.js b/awx/ui/static/js/widgets/JobStatusGraph.js deleted file mode 100644 index d83098a55c..0000000000 --- a/awx/ui/static/js/widgets/JobStatusGraph.js +++ /dev/null @@ -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 = "
\n"; - - html = "
\n"; - html += "
Job Status
\n"; // for All Jobs, Past Month - - html += "
\n"; - html += "
\n"; - html += "Job Type: \n"; - html += "All\n"; - html += " \n"; - - html += "\n"; - html += "
\n"; - - html += "
\n"; //end of filter div - - html += "
\n"; - html += "
\n"; - html += "Period: \n"; - html += "Past Month\n"; - html += " \n"; - - html += "\n"; - html += "
\n"; - html += "
\n"; //end of filter div - - html += "
\n"; // end of row - - html +="
\n"; - html += "
\n"; - html += "
\n"; - - // html += "
\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(""+this.text+"\n"); - - createGraph(); - }); - - //On click, update with new data - d3.selectAll(".m") - .on("click", function() { - job_type = this.getAttribute("id"); - $('#type-dropdown').replaceWith(""+this.text+"\n"); - - createGraph(); - }); - - scope.$emit('WidgetLoaded'); - return job_status_chart; - - }, - - - }); - - }); - - }; - } - ]); diff --git a/awx/ui/static/less/ansible-ui.less b/awx/ui/static/less/ansible-ui.less index f0dae5bc79..20ae33f979 100644 --- a/awx/ui/static/less/ansible-ui.less +++ b/awx/ui/static/less/ansible-ui.less @@ -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; +} diff --git a/awx/ui/static/lib/javascript-detect-element-resize/.bower.json b/awx/ui/static/lib/javascript-detect-element-resize/.bower.json index d9ba4f7d25..b65096ef42 100644 --- a/awx/ui/static/lib/javascript-detect-element-resize/.bower.json +++ b/awx/ui/static/lib/javascript-detect-element-resize/.bower.json @@ -30,4 +30,4 @@ "_source": "git://github.com/sdecima/javascript-detect-element-resize.git", "_target": "~0.5.3", "_originalSource": "javascript-detect-element-resize" -} \ No newline at end of file +} diff --git a/awx/ui/static/lib/javascript-detect-element-resize/jquery.resize.js b/awx/ui/static/lib/javascript-detect-element-resize/jquery.resize.js index ba42a80058..d6a6827ce0 100644 --- a/awx/ui/static/lib/javascript-detect-element-resize/jquery.resize.js +++ b/awx/ui/static/lib/javascript-detect-element-resize/jquery.resize.js @@ -10,9 +10,9 @@ (function ( $ ) { var attachEvent = document.attachEvent, stylesCreated = false; - + var jQuery_resize = $.fn.resize; - + $.fn.resize = function(callback) { return this.each(function() { if(this == window) @@ -27,14 +27,14 @@ removeResizeListener(this, callback); }); } - + if (!attachEvent) { var requestFrame = (function(){ var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || function(fn){ return window.setTimeout(fn, 20); }; return function(fn){ return raf(fn); }; })(); - + var cancelFrame = (function(){ var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame || window.clearTimeout; @@ -58,7 +58,7 @@ return element.offsetWidth != element.__resizeLast__.width || element.offsetHeight != element.__resizeLast__.height; } - + function scrollListener(e){ var element = this; resetTriggers(this); @@ -73,7 +73,7 @@ } }); }; - + /* Detect CSS Animations support to detect element display/re-attach */ var animation = false, animationstring = 'animation', @@ -84,8 +84,8 @@ pfx = ''; { var elm = document.createElement('fakeelement'); - if( elm.style.animationName !== undefined ) { animation = true; } - + if( elm.style.animationName !== undefined ) { animation = true; } + if( animation === false ) { for( var i = 0; i < domPrefixes.length; i++ ) { if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) { @@ -99,12 +99,12 @@ } } } - + var animationName = 'resizeanim'; var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } '; var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; '; } - + function createStyles() { if (!stylesCreated) { //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%; }', head = document.head || document.getElementsByTagName('head')[0], style = document.createElement('style'); - + style.type = 'text/css'; if (style.styleSheet) { style.styleSheet.cssText = css; @@ -125,7 +125,7 @@ stylesCreated = true; } } - + window.addResizeListener = function(element, fn){ if (attachEvent) element.attachEvent('onresize', fn); else { @@ -140,7 +140,7 @@ element.appendChild(element.__resizeTriggers__); resetTriggers(element); element.addEventListener('scroll', scrollListener, true); - + /* Listen for a css animation to detect element display/re-attach */ animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) { if(e.animationName == animationName) @@ -150,7 +150,7 @@ element.__resizeListeners__.push(fn); } }; - + window.removeResizeListener = function(element, fn){ if (attachEvent) element.detachEvent('onresize', fn); else { @@ -161,4 +161,4 @@ } } } -}( jQuery )); \ No newline at end of file +}( jQuery )); diff --git a/awx/ui/static/lib/nvd3/build/nv.d3.js b/awx/ui/static/lib/nvd3/build/nv.d3.js index f02b6d6aa6..0e27f9f1d5 100644 --- a/awx/ui/static/lib/nvd3/build/nv.d3.js +++ b/awx/ui/static/lib/nvd3/build/nv.d3.js @@ -11354,4 +11354,4 @@ nv.models.stackedAreaChart = function() { }; nv.version = "1.7.1"; -})(); \ No newline at end of file +})(); diff --git a/awx/ui/static/partials/home.html b/awx/ui/static/partials/home.html index 21ce6c07c2..c1c9c849db 100644 --- a/awx/ui/static/partials/home.html +++ b/awx/ui/static/partials/home.html @@ -1,58 +1,35 @@
-
-
+
+
-
- - - - -
-
- -
-
-
-
-
-
- -
+
+ + +
+
-
-
- -
-
-
-
-
-
-
- -
-
-
-
-
-
+ +
+
+ + diff --git a/awx/ui/static/partials/host_count_graph.html b/awx/ui/static/partials/host_count_graph.html deleted file mode 100644 index 3b154ab50a..0000000000 --- a/awx/ui/static/partials/host_count_graph.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
-
- Host Count -
-
- -
- -
-
- diff --git a/awx/ui/static/partials/host_status_graph.html b/awx/ui/static/partials/host_status_graph.html deleted file mode 100644 index 57193bf023..0000000000 --- a/awx/ui/static/partials/host_status_graph.html +++ /dev/null @@ -1,12 +0,0 @@ -
-
-
- Host Status -
-
- -
- -
-
- diff --git a/awx/ui/static/partials/job_status_graph.html b/awx/ui/static/partials/job_status_graph.html deleted file mode 100644 index c57c242b30..0000000000 --- a/awx/ui/static/partials/job_status_graph.html +++ /dev/null @@ -1,39 +0,0 @@ -
- diff --git a/config/awx-munin.conf b/config/awx-munin.conf index 833a6f36bf..90c479f77a 100644 --- a/config/awx-munin.conf +++ b/config/awx-munin.conf @@ -1,12 +1,17 @@ -Alias /munin /var/www/html/munin/ - + +Alias /munin /var/cache/munin/www + Order Allow,Deny Allow from all + Options FollowSymLinks AuthUserFile /var/lib/awx/.munin_htpasswd AuthName "Munin" AuthType Basic require valid-user + + ExpiresActive On + ExpiresDefault M310 + -ScriptAlias /munin-cgi/munin-cgi-graph /var/www/cgi-bin/munin-cgi-graph \ No newline at end of file