mirror of
https://github.com/ansible/awx.git
synced 2026-01-14 11:20:39 -03:30
adding workflow status bar to workflow results
This commit is contained in:
parent
9cb002b4cb
commit
478fc33710
@ -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);
|
||||
}])
|
||||
|
||||
@ -164,136 +164,6 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- STATUS DETAIL -->
|
||||
<!-- <div
|
||||
class="form-group
|
||||
WorkflowResults-resultRow
|
||||
toggle-show">
|
||||
<label
|
||||
class="WorkflowResults-resultRowLabel
|
||||
col-lg-2 col-md-2
|
||||
col-sm-2 col-xs-3
|
||||
control-label">
|
||||
Status
|
||||
</label>
|
||||
<div class="WorkflowResults-resultRowText
|
||||
col-lg-10 col-md-10 col-sm-10 col-xs-9">
|
||||
<i
|
||||
class="WorkflowResults-statusIcon--results
|
||||
fa
|
||||
icon-job-{{ job.status }}">
|
||||
</i> {{ status_label }}
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- SCHEDULED BY DETAIL -->
|
||||
<!-- <div
|
||||
class="form-group
|
||||
WorkflowResults-resultRow toggle-show"
|
||||
ng-show="workflow.summary_fields.schedule_by.username">
|
||||
<label
|
||||
class="WorkflowResults-resultRowLabel
|
||||
col-lg-2 col-md-2
|
||||
col-sm-2 col-xs-3
|
||||
control-label">
|
||||
Launched By
|
||||
</label>
|
||||
<div class="WorkflowResults-resultRowText">
|
||||
<a href="{{ scheduled_by_link }}"
|
||||
aw-tool-tip="Edit the Schedule"
|
||||
data-placement="top">
|
||||
{{ job.summary_fields.scheduled_by.username }}
|
||||
</a>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- ELAPSED TIME DETAIL -->
|
||||
<!-- <div
|
||||
class="form-group
|
||||
WorkflowResults-resultRow toggle-show"
|
||||
ng-show="workflow_status.started">
|
||||
<label
|
||||
class="WorkflowResults-resultRowLabel
|
||||
col-lg-2 col-md-2
|
||||
col-sm-2 col-xs-3
|
||||
control-label">
|
||||
Elapsed
|
||||
</label>
|
||||
<div class="WorkflowResults-resultRowText">
|
||||
{{ job_status.elapsed }}
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<!-- EXPLANATION DETAIL -->
|
||||
<!-- <div
|
||||
class="form-group
|
||||
WorkflowResults-resultRow
|
||||
toggle-show"
|
||||
ng-show="workflow_status.explanation">
|
||||
<label
|
||||
class="WorkflowResults-resultRowLabel
|
||||
col-lg-2 col-md-2
|
||||
col-sm-2 col-xs-3
|
||||
control-label">
|
||||
Explanation
|
||||
</label> -->
|
||||
|
||||
<!-- PREVIOUS TASK SUCCEEDED -->
|
||||
<!-- <div class="WorkflowResults-resultRowText
|
||||
col-lg-10 col-md-10 col-sm-10 col-xs-9
|
||||
job_status_explanation"
|
||||
ng-show="!previousTaskFailed"
|
||||
ng-bind-html="job_status.explanation">
|
||||
<i
|
||||
class="WorkflowResults-statusIcon--results
|
||||
fa
|
||||
icon-job-{{ job_status.status }}">
|
||||
</i> {{ job_status.status_label }}
|
||||
</div> -->
|
||||
|
||||
<!-- PREVIOUS TASK FAILED -->
|
||||
<!-- <div class="WorkflowResults-resultRowText
|
||||
col-lg-10 col-md-10 col-sm-10 col-xs-9
|
||||
job_status_explanation"
|
||||
ng-show="previousTaskFailed">
|
||||
Previous Task Failed
|
||||
<a
|
||||
href=""
|
||||
id="explanation_help"
|
||||
aw-pop-over="{{ task_detail }}"
|
||||
aw-pop-over-watch="task_detail"
|
||||
data-placement="bottom"
|
||||
data-container="body"
|
||||
class="help-link"
|
||||
over-title="Failure Detail"
|
||||
title=""
|
||||
tabindex="-1">
|
||||
<i class="fa fa-question-circle">
|
||||
</i>
|
||||
</a>
|
||||
</div> -->
|
||||
|
||||
<!-- </div> -->
|
||||
|
||||
<!-- RESULTS TRACEBACK DETAIL -->
|
||||
<!-- <div
|
||||
class="form-group
|
||||
WorkflowResults-resultRow
|
||||
toggle-show" ng-show="workflow.result_traceback">
|
||||
<label
|
||||
class="WorkflowResults-resultRowLabel
|
||||
col-lg-2 col-md-12
|
||||
col-sm-12 col-xs-12">
|
||||
Results Traceback
|
||||
</label>
|
||||
<div class="WorkflowResults-resultRowText
|
||||
col-lg-10 col-md-12 col-sm-12 col-xs-12
|
||||
job_status_traceback"
|
||||
ng-bind-html="job.result_traceback">
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -319,7 +189,7 @@
|
||||
Total Jobs
|
||||
</div>
|
||||
<span class="badge List-titleBadge">
|
||||
{{ workflow_nodes.count || 0}}
|
||||
{{ workflow_nodes.length || 0}}
|
||||
</span>
|
||||
|
||||
<!-- ELAPSED TIME -->
|
||||
@ -357,7 +227,7 @@
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<host-status-bar></host-status-bar>
|
||||
<workflow-status-bar></workflow-status-bar>
|
||||
<!-- <job-results-standard-out></job-results-standard-out> -->
|
||||
</div>
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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: `<div class='Prompt-bodyQuery'>
|
||||
Are you sure you want to delete the job below?
|
||||
Are you sure you want to delete the workflow below?
|
||||
</div>
|
||||
<div class='Prompt-bodyTarget'>
|
||||
#${job.id} ${$filter('sanitize')(job.name)}
|
||||
#${workflow.id} ${$filter('sanitize')(workflow.name)}
|
||||
</div>`,
|
||||
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: `<div class='Prompt-bodyQuery'>
|
||||
Are you sure you want to cancel the job below?
|
||||
Are you sure you want to cancel the workflow below?
|
||||
</div>
|
||||
<div class='Prompt-bodyTarget'>
|
||||
#${job.id} ${$filter('sanitize')(job.name)}
|
||||
#${workflow.id} ${$filter('sanitize')(workflow.name)}
|
||||
</div>`,
|
||||
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 });
|
||||
}
|
||||
};
|
||||
|
||||
@ -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);
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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`] = `<span class='WorkflowStatusBar-tooltipLabel'>${key}</span><span class='badge WorkflowStatusBar-tooltipBadge WorkflowStatusBar-tooltipBadge--${key}'>${val[key]}</span>`;
|
||||
}
|
||||
});
|
||||
|
||||
// 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);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}];
|
||||
@ -0,0 +1,26 @@
|
||||
<div class="WorkflowStatusBar">
|
||||
<div class="WorkflowStatusBar-ok"
|
||||
data-placement="top"
|
||||
aw-tool-tip="{{okCountTip}}"
|
||||
data-tip-watch="okCountTip"></div>
|
||||
<div class="WorkflowStatusBar-changed"
|
||||
data-placement="top"
|
||||
aw-tool-tip="{{changedCountTip}}"
|
||||
data-tip-watch="changedCountTip"></div>
|
||||
<div class="WorkflowStatusBar-failures"
|
||||
data-placement="top"
|
||||
aw-tool-tip="{{failuresCountTip}}"
|
||||
data-tip-watch="failuresCountTip"></div>
|
||||
<div class="WorkflowStatusBar-unreachable"
|
||||
data-placement="top"
|
||||
aw-tool-tip="{{unreachableCountTip}}"
|
||||
data-tip-watch="unreachableCountTip"></div>
|
||||
<div class="WorkflowStatusBar-skipped"
|
||||
data-placement="top"
|
||||
aw-tool-tip="{{skippedCountTip}}"
|
||||
data-tip-watch="skippedCountTip"></div>
|
||||
<div class="WorkflowStatusBar-noData"
|
||||
aw-tool-tip="NO HOSTS FINISHED"
|
||||
ng-hide="hostsFinished"
|
||||
data-placement="top"></div>
|
||||
</div>
|
||||
Loading…
x
Reference in New Issue
Block a user