diff --git a/awx/ui/client/src/workflow-results/main.js b/awx/ui/client/src/workflow-results/main.js index 6e6d775dea..7faf366fc9 100644 --- a/awx/ui/client/src/workflow-results/main.js +++ b/awx/ui/client/src/workflow-results/main.js @@ -4,13 +4,12 @@ * All Rights Reserved *************************************************/ - +import workflowStatusBar from './workflow-status-bar/main'; import route from './workflow-results.route.js'; - import workflowResultsService from './workflow-results.service'; export default - angular.module('workflowResults', []) + angular.module('workflowResults', [workflowStatusBar.name]) .run(['$stateExtender', function($stateExtender) { $stateExtender.addState(route); }]) diff --git a/awx/ui/client/src/workflow-results/workflow-results.partial.html b/awx/ui/client/src/workflow-results/workflow-results.partial.html index a418451de7..9612719221 100644 --- a/awx/ui/client/src/workflow-results/workflow-results.partial.html +++ b/awx/ui/client/src/workflow-results/workflow-results.partial.html @@ -164,136 +164,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - @@ -319,7 +189,7 @@ Total Jobs - {{ workflow_nodes.count || 0}} + {{ workflow_nodes.length || 0}} @@ -357,7 +227,7 @@ - + diff --git a/awx/ui/client/src/workflow-results/workflow-results.route.js b/awx/ui/client/src/workflow-results/workflow-results.route.js index a9b4dfd70a..8ccf016a4a 100644 --- a/awx/ui/client/src/workflow-results/workflow-results.route.js +++ b/awx/ui/client/src/workflow-results/workflow-results.route.js @@ -56,7 +56,7 @@ export default { Rest.setUrl(workflowData.related.workflow_nodes); Rest.get() .success(function(data) { - defer.resolve(data.data); + defer.resolve(data.results); }) .error(function() { defer.resolve(data); diff --git a/awx/ui/client/src/workflow-results/workflow-results.service.js b/awx/ui/client/src/workflow-results/workflow-results.service.js index 3ca6019587..5eb1dee19a 100644 --- a/awx/ui/client/src/workflow-results/workflow-results.service.js +++ b/awx/ui/client/src/workflow-results/workflow-results.service.js @@ -7,102 +7,14 @@ export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErrors', 'InitiatePlaybookRun', function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybookRun) { var val = { - // the playbook_on_stats event returns the count data in a weird format. - // format to what we need! - getCountsFromStatsEvent: function(event_data) { - var hosts = {}, - hostsArr; - - // iterate over the event_data and populate an object with hosts - // and their status data - Object.keys(event_data).forEach(key => { - // failed passes boolean not integer - if (key === "failed") { - // array of hosts from failed type - hostsArr = Object.keys(event_data[key]); - hostsArr.forEach(host => { - if (!hosts[host]) { - // host has not been added to hosts object - // add now - hosts[host] = {}; - } - - hosts[host][key] = event_data[key][host]; - }); - } else { - // array of hosts from each type ("changed", "dark", etc.) - hostsArr = Object.keys(event_data[key]); - hostsArr.forEach(host => { - if (!hosts[host]) { - // host has not been added to hosts object - // add now - hosts[host] = {}; - } - - if (!hosts[host][key]) { - // host doesn't have key - hosts[host][key] = 0; - } - hosts[host][key] += event_data[key][host]; - }); - } - }); - - // use the hosts data populate above to get the count - var count = { - ok : _.filter(hosts, function(o){ - return !o.failures && !o.changed && o.ok > 0; - }), - skipped : _.filter(hosts, function(o){ - return o.skipped > 0; - }), - unreachable : _.filter(hosts, function(o){ - return o.dark > 0; - }), - failures : _.filter(hosts, function(o){ - return o.failed === true; - }), - changed : _.filter(hosts, function(o){ - return o.changed > 0; - }) - }; - - // turn the count into an actual count, rather than a list of host - // names - Object.keys(count).forEach(key => { - count[key] = count[key].length; - }); - - return count; - }, - getEvents: function(url) { - var val = $q.defer(); - - Rest.setUrl(url); - Rest.get() - .success(function(data) { - val.resolve({results: data.results, - next: data.next}); - }) - .error(function(obj, status) { - ProcessErrors(null, obj, status, null, { - hdr: 'Error!', - msg: `Could not get job events. - Returned status: ${status}` - }); - val.reject(obj); - }); - - return val.promise; - }, - deleteJob: function(job) { + deleteJob: function(workflow) { Prompt({ hdr: 'Delete Job', body: `
- Are you sure you want to delete the job below? + Are you sure you want to delete the workflow below?
- #${job.id} ${$filter('sanitize')(job.name)} + #${workflow.id} ${$filter('sanitize')(workflow.name)}
`, action: function() { Wait('start'); @@ -126,9 +38,9 @@ export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErr actionText: 'DELETE' }); }, - cancelJob: function(job) { + cancelJob: function(workflow) { var doCancel = function() { - Rest.setUrl(job.url + 'cancel'); + Rest.setUrl(workflow.url + 'cancel'); Rest.post({}) .success(function() { Wait('stop'); @@ -139,23 +51,23 @@ export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErr $('#prompt-modal').modal('hide'); ProcessErrors(null, obj, status, null, { hdr: 'Error!', - msg: `Could not cancel job. + msg: `Could not cancel workflow. Returned status: ${status}` }); }); }; Prompt({ - hdr: 'Cancel Job', + hdr: 'Cancel Workflow', body: `
- Are you sure you want to cancel the job below? + Are you sure you want to cancel the workflow below?
- #${job.id} ${$filter('sanitize')(job.name)} + #${workflow.id} ${$filter('sanitize')(workflow.name)}
`, action: function() { Wait('start'); - Rest.setUrl(job.url + 'cancel'); + Rest.setUrl(workflow.url + 'cancel'); Rest.get() .success(function(data) { if (data.can_cancel === true) { @@ -179,7 +91,7 @@ export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErr $('#prompt-modal').modal('hide'); ProcessErrors(null, obj, status, null, { hdr: 'Error!', - msg: `Could not cancel job. + msg: `Could not cancel workflow. Returned status: ${status}` }); }); @@ -188,7 +100,7 @@ export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErr }); }, relaunchJob: function(scope) { - InitiatePlaybookRun({ scope: scope, id: scope.job.id, + InitiatePlaybookRun({ scope: scope, id: scope.workflow.id, relaunch: true }); } }; diff --git a/awx/ui/client/src/workflow-results/workflow-status-bar/main.js b/awx/ui/client/src/workflow-results/workflow-status-bar/main.js new file mode 100644 index 0000000000..251258fc70 --- /dev/null +++ b/awx/ui/client/src/workflow-results/workflow-status-bar/main.js @@ -0,0 +1,11 @@ +/************************************************* + * Copyright (c) 2015 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import workflowStatusBar from './workflow-status-bar.directive'; + +export default + angular.module('workflowStatusBarDirective', []) + .directive('workflowStatusBar', workflowStatusBar); diff --git a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.block.less b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.block.less new file mode 100644 index 0000000000..38e57d4883 --- /dev/null +++ b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.block.less @@ -0,0 +1,80 @@ +@import '../../shared/branding/colors.default.less'; + +.WorkflowStatusBar { + display: flex; + flex: 0 0 auto; + width: 100%; + margin-top: 10px; +} + +.WorkflowStatusBar-ok, +.WorkflowStatusBar-changed, +.WorkflowStatusBar-unreachable, +.WorkflowStatusBar-failures, +.WorkflowStatusBar-skipped, +.WorkflowStatusBar-noData { + height: 15px; + border-top: 5px solid @default-bg; + border-bottom: 5px solid @default-bg; +} + +.WorkflowStatusBar-ok { + background-color: @default-succ; + display: flex; + flex: 0 0 auto; +} + +.WorkflowStatusBar-changed { + background-color: @default-warning; + flex: 0 0 auto; +} + +.WorkflowStatusBar-unreachable { + background-color: @default-unreachable; + flex: 0 0 auto; +} + +.WorkflowStatusBar-failures { + background-color: @default-err; + flex: 0 0 auto; +} + +.WorkflowStatusBar-skipped { + background-color: @default-link; + flex: 0 0 auto; +} + +.WorkflowStatusBar-noData { + background-color: @default-icon-hov; + flex: 1 0 auto; +} + +.WorkflowStatusBar-tooltipLabel { + text-transform: uppercase; + margin-right: 15px; +} + +.WorkflowStatusBar-tooltipBadge { + border-radius: 5px; +} + +.WorkflowStatusBar-tooltipBadge--ok { + background-color: @default-succ; +} + +.WorkflowStatusBar-tooltipBadge--unreachable { + background-color: @default-unreachable; +} + +.WorkflowStatusBar-tooltipBadge--skipped { + background-color: @default-link; +} + +.WorkflowStatusBar-tooltipBadge--changed { + background-color: @default-warning; +} + +.WorkflowStatusBar-tooltipBadge--failures { + background-color: @default-err; + +} diff --git a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.directive.js b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.directive.js new file mode 100644 index 0000000000..a6899eb0da --- /dev/null +++ b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.directive.js @@ -0,0 +1,43 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +// import WorkflowStatusBarController from './host-status-bar.controller'; +export default [ 'templateUrl', + function(templateUrl) { + return { + scope: true, + templateUrl: templateUrl('workflow-results/workflow-status-bar/workflow-status-bar'), + restrict: 'E', + // controller: standardOutLogController, + link: function(scope) { + // as count is changed by event data coming in, + // update the host status bar + scope.$watch('count', function(val) { + if (val) { + Object.keys(val).forEach(key => { + // reposition the hosts status bar by setting + // the various flex values to the count of + // those hosts + $(`.WorkflowStatusBar-${key}`) + .css('flex', `${val[key]} 0 auto`); + + // set the tooltip to give how many hosts of + // each type + if (val[key] > 0) { + scope[`${key}CountTip`] = `${key}${val[key]}`; + } + }); + + // if there are any hosts that have finished, don't + // show default grey bar + scope.hostsFinished = (Object + .keys(val) + .filter(key => (val[key] > 0)).length > 0); + } + }); + } + }; +}]; diff --git a/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.partial.html b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.partial.html new file mode 100644 index 0000000000..e0efddc7b6 --- /dev/null +++ b/awx/ui/client/src/workflow-results/workflow-status-bar/workflow-status-bar.partial.html @@ -0,0 +1,26 @@ +
+
+
+
+
+
+
+