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 @@
+