Merge pull request #5125 from chrismeyersfsu/fix-4851

workflow job elapsed timer
This commit is contained in:
Chris Meyers 2017-02-03 11:39:59 -05:00 committed by GitHub
commit aa83bda3ca
10 changed files with 1211 additions and 12 deletions

View File

@ -7,10 +7,12 @@
import workflowStatusBar from './workflow-status-bar/main';
import route from './workflow-results.route.js';
import workflowResultsService from './workflow-results.service';
import controller from './workflow-results.controller';
export default
angular.module('workflowResults', [workflowStatusBar.name])
.run(['$stateExtender', function($stateExtender) {
$stateExtender.addState(route);
}])
.controller('workflowResultsController', controller)
.service('workflowResultsService', workflowResultsService);

View File

@ -10,6 +10,7 @@ export default ['workflowData',
'count',
'$state',
'i18n',
'moment',
function(workflowData,
workflowResultsService,
workflowDataOptions,
@ -21,8 +22,10 @@ export default ['workflowData',
WorkflowService,
count,
$state,
i18n
i18n,
moment
) {
var runTimeElapsedTimer = null;
var getTowerLinks = function() {
var getTowerLink = function(key) {
@ -67,6 +70,10 @@ export default ['workflowData',
$scope.verbosity_label = getTowerLabel('verbosity');
};
var updateWorkflowJobElapsedTimer = function(time) {
$scope.workflow.elapsed = time;
};
function init() {
// put initially resolved request data on scope
$scope.workflow = workflowData;
@ -76,6 +83,11 @@ export default ['workflowData',
$scope.count = count.val;
$scope.showManualControls = false;
// Start elapsed time updater for job known to be running
if ($scope.workflow.started !== null && $scope.workflow.status === 'running') {
runTimeElapsedTimer = workflowResultsService.createOneSecondTimer($scope.workflow.started, updateWorkflowJobElapsedTimer);
}
// stdout full screen toggle tooltip text
$scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output");
@ -179,8 +191,12 @@ export default ['workflowData',
// Update the workflow job's unified job:
if (parseInt(data.unified_job_id, 10) === parseInt($scope.workflow.id,10)) {
$scope.workflow.status = data.status;
// start internval counter for job that transitioned to running
if ($scope.workflow.status === 'running') {
runTimeElapsedTimer = workflowResultsService.createOneSecondTimer(moment(), updateWorkflowJobElapsedTimer);
}
if(data.status === "successful" || data.status === "failed"){
if(data.status === "successful" || data.status === "failed" || data.status === "error"){
$state.go('.', null, { reload: true });
}
}
@ -208,4 +224,8 @@ export default ['workflowData',
$scope.$broadcast("refreshWorkflowChart");
}
});
$scope.$on('$destroy', function() {
workflowResultsService.destroyTimer(runTimeElapsedTimer);
});
}];

View File

@ -5,7 +5,7 @@
*************************************************/
export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErrors', 'InitiatePlaybookRun', function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybookRun) {
export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErrors', 'InitiatePlaybookRun', '$interval', 'moment', function ($q, Prompt, $filter, Wait, Rest, $state, ProcessErrors, InitiatePlaybookRun, $interval, moment) {
var val = {
getCounts: function(workflowNodes){
var nodeArr = [];
@ -127,7 +127,20 @@ export default ['$q', 'Prompt', '$filter', 'Wait', 'Rest', '$state', 'ProcessErr
relaunchJob: function(scope) {
InitiatePlaybookRun({ scope: scope, id: scope.workflow.id,
relaunch: true, job_type: 'workflow_job' });
}
},
createOneSecondTimer: function(startTime, fn) {
return $interval(function(){
fn(moment().diff(moment(startTime), 'seconds'));
}, 1000);
},
destroyTimer: function(timer) {
if (timer !== null) {
$interval.cancel(timer);
timer = null;
return true;
}
return false;
},
};
return val;
}];

View File

@ -20,6 +20,7 @@ module.exports = function(config) {
'./client/src/app.js',
'./node_modules/angular-mocks/angular-mocks.js',
{ pattern: './tests/**/*-test.js' },
{ pattern: './tests/**/*.json', included: false},
'client/src/**/*.html'
],
preprocessors: {

View File

@ -2000,6 +2000,708 @@
"from": "fs.realpath@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
},
"fsevents": {
"version": "1.0.17",
"from": "fsevents@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.0.17.tgz",
"optional": true,
"dependencies": {
"abbrev": {
"version": "1.0.9",
"from": "abbrev@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",
"optional": true
},
"ansi-regex": {
"version": "2.0.0",
"from": "ansi-regex@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz"
},
"ansi-styles": {
"version": "2.2.1",
"from": "ansi-styles@>=2.2.1 <3.0.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"optional": true
},
"aproba": {
"version": "1.0.4",
"from": "aproba@>=1.0.3 <2.0.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz",
"optional": true
},
"are-we-there-yet": {
"version": "1.1.2",
"from": "are-we-there-yet@>=1.1.2 <1.2.0",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz",
"optional": true
},
"asn1": {
"version": "0.2.3",
"from": "asn1@>=0.2.3 <0.3.0",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
"optional": true
},
"assert-plus": {
"version": "0.2.0",
"from": "assert-plus@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
"optional": true
},
"asynckit": {
"version": "0.4.0",
"from": "asynckit@>=0.4.0 <0.5.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"optional": true
},
"aws-sign2": {
"version": "0.6.0",
"from": "aws-sign2@>=0.6.0 <0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
"optional": true
},
"aws4": {
"version": "1.5.0",
"from": "aws4@>=1.2.1 <2.0.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz",
"optional": true
},
"balanced-match": {
"version": "0.4.2",
"from": "balanced-match@>=0.4.1 <0.5.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz"
},
"bcrypt-pbkdf": {
"version": "1.0.0",
"from": "bcrypt-pbkdf@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz",
"optional": true
},
"block-stream": {
"version": "0.0.9",
"from": "block-stream@*",
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz"
},
"boom": {
"version": "2.10.1",
"from": "boom@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
},
"brace-expansion": {
"version": "1.1.6",
"from": "brace-expansion@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz"
},
"buffer-shims": {
"version": "1.0.0",
"from": "buffer-shims@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz"
},
"caseless": {
"version": "0.11.0",
"from": "caseless@>=0.11.0 <0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz",
"optional": true
},
"chalk": {
"version": "1.1.3",
"from": "chalk@>=1.1.1 <2.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"optional": true,
"dependencies": {
"supports-color": {
"version": "2.0.0",
"from": "supports-color@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"optional": true
}
}
},
"code-point-at": {
"version": "1.1.0",
"from": "code-point-at@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz"
},
"combined-stream": {
"version": "1.0.5",
"from": "combined-stream@>=1.0.5 <1.1.0",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
},
"commander": {
"version": "2.9.0",
"from": "commander@>=2.9.0 <3.0.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
"optional": true
},
"concat-map": {
"version": "0.0.1",
"from": "concat-map@0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
},
"console-control-strings": {
"version": "1.1.0",
"from": "console-control-strings@>=1.1.0 <1.2.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz"
},
"core-util-is": {
"version": "1.0.2",
"from": "core-util-is@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
},
"cryptiles": {
"version": "2.0.5",
"from": "cryptiles@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
"optional": true
},
"dashdash": {
"version": "1.14.1",
"from": "dashdash@>=1.12.0 <2.0.0",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"optional": true,
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"from": "assert-plus@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"optional": true
}
}
},
"debug": {
"version": "2.2.0",
"from": "debug@>=2.2.0 <2.3.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
"optional": true
},
"deep-extend": {
"version": "0.4.1",
"from": "deep-extend@>=0.4.0 <0.5.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.1.tgz",
"optional": true
},
"delayed-stream": {
"version": "1.0.0",
"from": "delayed-stream@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
},
"delegates": {
"version": "1.0.0",
"from": "delegates@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"optional": true
},
"ecc-jsbn": {
"version": "0.1.1",
"from": "ecc-jsbn@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
"optional": true
},
"escape-string-regexp": {
"version": "1.0.5",
"from": "escape-string-regexp@>=1.0.2 <2.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"optional": true
},
"extend": {
"version": "3.0.0",
"from": "extend@>=3.0.0 <3.1.0",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz",
"optional": true
},
"extsprintf": {
"version": "1.0.2",
"from": "extsprintf@1.0.2",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
},
"forever-agent": {
"version": "0.6.1",
"from": "forever-agent@>=0.6.1 <0.7.0",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"optional": true
},
"form-data": {
"version": "2.1.2",
"from": "form-data@>=2.1.1 <2.2.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz",
"optional": true
},
"fs.realpath": {
"version": "1.0.0",
"from": "fs.realpath@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
},
"fstream": {
"version": "1.0.10",
"from": "fstream@>=1.0.2 <2.0.0",
"resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz"
},
"fstream-ignore": {
"version": "1.0.5",
"from": "fstream-ignore@>=1.0.5 <1.1.0",
"resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz",
"optional": true
},
"gauge": {
"version": "2.7.2",
"from": "gauge@>=2.7.1 <2.8.0",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.2.tgz",
"optional": true
},
"generate-function": {
"version": "2.0.0",
"from": "generate-function@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
"optional": true
},
"generate-object-property": {
"version": "1.2.0",
"from": "generate-object-property@>=1.1.0 <2.0.0",
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
"optional": true
},
"getpass": {
"version": "0.1.6",
"from": "getpass@>=0.1.1 <0.2.0",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz",
"optional": true,
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"from": "assert-plus@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"optional": true
}
}
},
"glob": {
"version": "7.1.1",
"from": "glob@>=7.0.5 <8.0.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
},
"graceful-fs": {
"version": "4.1.11",
"from": "graceful-fs@>=4.1.2 <5.0.0",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
},
"graceful-readlink": {
"version": "1.0.1",
"from": "graceful-readlink@>=1.0.0",
"resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
"optional": true
},
"har-validator": {
"version": "2.0.6",
"from": "har-validator@>=2.0.6 <2.1.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz",
"optional": true
},
"has-ansi": {
"version": "2.0.0",
"from": "has-ansi@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"optional": true
},
"has-unicode": {
"version": "2.0.1",
"from": "has-unicode@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"optional": true
},
"hawk": {
"version": "3.1.3",
"from": "hawk@>=3.1.3 <3.2.0",
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
"optional": true
},
"hoek": {
"version": "2.16.3",
"from": "hoek@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
},
"http-signature": {
"version": "1.1.1",
"from": "http-signature@>=1.1.0 <1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
"optional": true
},
"inflight": {
"version": "1.0.6",
"from": "inflight@>=1.0.4 <2.0.0",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
},
"inherits": {
"version": "2.0.3",
"from": "inherits@>=2.0.1 <2.1.0",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
},
"ini": {
"version": "1.3.4",
"from": "ini@>=1.3.0 <1.4.0",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"from": "is-fullwidth-code-point@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz"
},
"is-my-json-valid": {
"version": "2.15.0",
"from": "is-my-json-valid@>=2.12.4 <3.0.0",
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz",
"optional": true
},
"is-property": {
"version": "1.0.2",
"from": "is-property@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"optional": true
},
"is-typedarray": {
"version": "1.0.0",
"from": "is-typedarray@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"optional": true
},
"isarray": {
"version": "1.0.0",
"from": "isarray@>=1.0.0 <1.1.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
},
"isstream": {
"version": "0.1.2",
"from": "isstream@>=0.1.2 <0.2.0",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"optional": true
},
"jodid25519": {
"version": "1.0.2",
"from": "jodid25519@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
"optional": true
},
"jsbn": {
"version": "0.1.0",
"from": "jsbn@>=0.1.0 <0.2.0",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz",
"optional": true
},
"json-schema": {
"version": "0.2.3",
"from": "json-schema@0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"optional": true
},
"json-stringify-safe": {
"version": "5.0.1",
"from": "json-stringify-safe@>=5.0.1 <5.1.0",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"optional": true
},
"jsonpointer": {
"version": "4.0.1",
"from": "jsonpointer@>=4.0.0 <5.0.0",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
"optional": true
},
"jsprim": {
"version": "1.3.1",
"from": "jsprim@>=1.2.2 <2.0.0",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz",
"optional": true
},
"mime-db": {
"version": "1.25.0",
"from": "mime-db@>=1.25.0 <1.26.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.25.0.tgz"
},
"mime-types": {
"version": "2.1.13",
"from": "mime-types@>=2.1.7 <2.2.0",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.13.tgz"
},
"minimatch": {
"version": "3.0.3",
"from": "minimatch@>=3.0.2 <4.0.0",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
},
"minimist": {
"version": "0.0.8",
"from": "minimist@0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
},
"mkdirp": {
"version": "0.5.1",
"from": "mkdirp@>=0.5.1 <0.6.0",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
},
"ms": {
"version": "0.7.1",
"from": "ms@0.7.1",
"resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
"optional": true
},
"node-pre-gyp": {
"version": "0.6.32",
"from": "node-pre-gyp@>=0.6.29 <0.7.0",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz",
"optional": true
},
"nopt": {
"version": "3.0.6",
"from": "nopt@>=3.0.6 <3.1.0",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
"optional": true
},
"npmlog": {
"version": "4.0.2",
"from": "npmlog@>=4.0.1 <5.0.0",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz",
"optional": true
},
"number-is-nan": {
"version": "1.0.1",
"from": "number-is-nan@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz"
},
"oauth-sign": {
"version": "0.8.2",
"from": "oauth-sign@>=0.8.1 <0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
"optional": true
},
"object-assign": {
"version": "4.1.0",
"from": "object-assign@>=4.1.0 <5.0.0",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
"optional": true
},
"once": {
"version": "1.4.0",
"from": "once@>=1.3.0 <2.0.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
},
"path-is-absolute": {
"version": "1.0.1",
"from": "path-is-absolute@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
},
"pinkie": {
"version": "2.0.4",
"from": "pinkie@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
"optional": true
},
"pinkie-promise": {
"version": "2.0.1",
"from": "pinkie-promise@>=2.0.0 <3.0.0",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"optional": true
},
"process-nextick-args": {
"version": "1.0.7",
"from": "process-nextick-args@>=1.0.6 <1.1.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz"
},
"punycode": {
"version": "1.4.1",
"from": "punycode@>=1.4.1 <2.0.0",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"optional": true
},
"qs": {
"version": "6.3.0",
"from": "qs@>=6.3.0 <6.4.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.3.0.tgz",
"optional": true
},
"rc": {
"version": "1.1.6",
"from": "rc@>=1.1.6 <1.2.0",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.1.6.tgz",
"optional": true,
"dependencies": {
"minimist": {
"version": "1.2.0",
"from": "minimist@>=1.2.0 <2.0.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"optional": true
}
}
},
"readable-stream": {
"version": "2.2.2",
"from": "readable-stream@>=2.0.0 <3.0.0||>=1.1.13 <2.0.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz",
"optional": true
},
"request": {
"version": "2.79.0",
"from": "request@>=2.79.0 <3.0.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz",
"optional": true
},
"rimraf": {
"version": "2.5.4",
"from": "rimraf@>=2.5.4 <2.6.0",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz"
},
"semver": {
"version": "5.3.0",
"from": "semver@>=5.3.0 <5.4.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"from": "set-blocking@>=2.0.0 <2.1.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"from": "signal-exit@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"optional": true
},
"sntp": {
"version": "1.0.9",
"from": "sntp@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
"optional": true
},
"sshpk": {
"version": "1.10.1",
"from": "sshpk@>=1.7.0 <2.0.0",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.1.tgz",
"optional": true,
"dependencies": {
"assert-plus": {
"version": "1.0.0",
"from": "assert-plus@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"optional": true
}
}
},
"string_decoder": {
"version": "0.10.31",
"from": "string_decoder@>=0.10.0 <0.11.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
},
"string-width": {
"version": "1.0.2",
"from": "string-width@>=1.0.1 <2.0.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz"
},
"stringstream": {
"version": "0.0.5",
"from": "stringstream@>=0.0.4 <0.1.0",
"resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
"optional": true
},
"strip-ansi": {
"version": "3.0.1",
"from": "strip-ansi@>=3.0.1 <4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz"
},
"strip-json-comments": {
"version": "1.0.4",
"from": "strip-json-comments@>=1.0.4 <1.1.0",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
"optional": true
},
"supports-color": {
"version": "0.2.0",
"from": "supports-color@>=0.2.0 <0.3.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz",
"optional": true
},
"tar": {
"version": "2.2.1",
"from": "tar@>=2.2.1 <2.3.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
},
"tar-pack": {
"version": "3.3.0",
"from": "tar-pack@>=3.3.0 <3.4.0",
"resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.3.0.tgz",
"optional": true,
"dependencies": {
"once": {
"version": "1.3.3",
"from": "once@>=1.3.3 <1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
"optional": true
},
"readable-stream": {
"version": "2.1.5",
"from": "readable-stream@>=2.1.4 <2.2.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz",
"optional": true
}
}
},
"tough-cookie": {
"version": "2.3.2",
"from": "tough-cookie@>=2.3.0 <2.4.0",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
"optional": true
},
"tunnel-agent": {
"version": "0.4.3",
"from": "tunnel-agent@>=0.4.1 <0.5.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz",
"optional": true
},
"tweetnacl": {
"version": "0.14.5",
"from": "tweetnacl@>=0.14.0 <0.15.0",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"optional": true
},
"uid-number": {
"version": "0.0.6",
"from": "uid-number@>=0.0.6 <0.1.0",
"resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
"optional": true
},
"util-deprecate": {
"version": "1.0.2",
"from": "util-deprecate@>=1.0.1 <1.1.0",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
},
"uuid": {
"version": "3.0.1",
"from": "uuid@>=3.0.0 <4.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz",
"optional": true
},
"verror": {
"version": "1.3.6",
"from": "verror@1.3.6",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
"optional": true
},
"wide-align": {
"version": "1.1.0",
"from": "wide-align@>=1.1.0 <2.0.0",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz",
"optional": true
},
"wrappy": {
"version": "1.0.2",
"from": "wrappy@>=1.0.0 <2.0.0",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
},
"xtend": {
"version": "4.0.1",
"from": "xtend@>=4.0.0 <5.0.0",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"optional": true
}
}
},
"gaze": {
"version": "1.1.2",
"from": "gaze@>=1.0.0 <2.0.0",
@ -2915,9 +3617,9 @@
"resolved": "https://registry.npmjs.org/jstimezonedetect/-/jstimezonedetect-1.0.5.tgz"
},
"karma": {
"version": "1.4.0",
"from": "karma@>=1.1.2 <2.0.0",
"resolved": "https://registry.npmjs.org/karma/-/karma-1.4.0.tgz",
"version": "1.4.1",
"from": "karma@1.4.1",
"resolved": "https://registry.npmjs.org/karma/-/karma-1.4.1.tgz",
"dev": true,
"dependencies": {
"after": {
@ -3100,7 +3802,7 @@
},
"karma-jasmine": {
"version": "1.1.0",
"from": "karma-jasmine@>=1.0.2 <2.0.0",
"from": "karma-jasmine@1.1.0",
"resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.0.tgz",
"dev": true
},

View File

@ -52,17 +52,17 @@
"grunt-newer": "^1.2.0",
"grunt-webpack": "^1.0.11",
"imports-loader": "^0.6.5",
"jasmine-core": "^2.4.1",
"jasmine-core": "^2.5.2",
"jshint": "^2.9.4",
"jshint-loader": "^0.8.3",
"jshint-stylish": "^2.2.0",
"karma": "^1.1.2",
"karma": "^1.4.1",
"karma-chrome-launcher": "^1.0.1",
"karma-coverage": "^1.1.1",
"karma-firefox-launcher": "^1.0.0",
"karma-html2js-preprocessor": "^1.0.0",
"karma-jasmine": "^1.0.2",
"karma-junit-reporter": "^1.1.0",
"karma-jasmine": "^1.1.0",
"karma-junit-reporter": "^1.2.0",
"karma-phantomjs-launcher": "^1.0.2",
"karma-sauce-launcher": "^1.0.0",
"karma-sourcemap-loader": "^0.3.7",

View File

@ -0,0 +1,63 @@
export default {
"id": 109,
"type": "workflow_job",
"url": "/api/v1/workflow_jobs/109/",
"related": {
"created_by": "/api/v1/users/1/",
"unified_job_template": "/api/v1/workflow_job_templates/27/",
"workflow_job_template": "/api/v1/workflow_job_templates/27/",
"notifications": "/api/v1/workflow_jobs/109/notifications/",
"workflow_nodes": "/api/v1/workflow_jobs/109/workflow_nodes/",
"labels": "/api/v1/workflow_jobs/109/labels/",
"activity_stream": "/api/v1/workflow_jobs/109/activity_stream/",
"relaunch": "/api/v1/workflow_jobs/109/relaunch/",
"cancel": "/api/v1/workflow_jobs/109/cancel/"
},
"summary_fields": {
"workflow_job_template": {
"id": 27,
"name": "workflow timer",
"description": ""
},
"unified_job_template": {
"id": 27,
"name": "workflow timer",
"description": "",
"unified_job_type": "workflow_job"
},
"created_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"user_capabilities": {
"start": true,
"delete": true
},
"labels": {
"count": 0,
"results": []
}
},
"created": "2017-02-01T14:56:47.416Z",
"modified": "2017-02-01T14:57:14.189Z",
"name": "workflow timer",
"description": "",
"unified_job_template": 27,
"launch_type": "manual",
"status": "successful",
"failed": false,
"started": "2017-02-01T14:56:47.754897Z",
"finished": "2017-02-01T14:57:14.182780Z",
"elapsed": 26.428,
"job_args": "",
"job_cwd": "",
"job_env": {},
"job_explanation": "",
"result_stdout": "stdout capture is missing",
"execution_node": "",
"result_traceback": "",
"workflow_job_template": 27,
"extra_vars": "{}"
};

View File

@ -0,0 +1,203 @@
export default {
"name": "Workflow Job Detail",
"description": "# Retrieve Workflow Job:\n\nMake GET request to this resource to retrieve a single workflow job\nrecord containing the following fields:\n\n* `id`: Database ID for this workflow job. (integer)\n* `type`: Data type for this workflow job. (choice)\n* `url`: URL for this workflow job. (string)\n* `related`: Data structure with URLs of related resources. (object)\n* `summary_fields`: Data structure with name/description for related resources. (object)\n* `created`: Timestamp when this workflow job was created. (datetime)\n* `modified`: Timestamp when this workflow job was last modified. (datetime)\n* `name`: Name of this workflow job. (string)\n* `description`: Optional description of this workflow job. (string)\n* `unified_job_template`: (field)\n* `launch_type`: (choice)\n - `manual`: Manual\n - `relaunch`: Relaunch\n - `callback`: Callback\n - `scheduled`: Scheduled\n - `dependency`: Dependency\n - `workflow`: Workflow\n - `sync`: Sync\n* `status`: (choice)\n - `new`: New\n - `pending`: Pending\n - `waiting`: Waiting\n - `running`: Running\n - `successful`: Successful\n - `failed`: Failed\n - `error`: Error\n - `canceled`: Canceled\n* `failed`: (boolean)\n* `started`: The date and time the job was queued for starting. (datetime)\n* `finished`: The date and time the job finished execution. (datetime)\n* `elapsed`: Elapsed time in seconds that the job ran. (decimal)\n* `job_args`: (string)\n* `job_cwd`: (string)\n* `job_env`: (field)\n* `job_explanation`: A status field to indicate the state of the job if it wasn&#39;t able to run and capture stdout (string)\n* `result_stdout`: (field)\n* `execution_node`: The Tower node the job executed on. (string)\n* `result_traceback`: (string)\n* `workflow_job_template`: (field)\n* `extra_vars`: (string)\n\n\n\n# Delete Workflow Job:\n\nMake a DELETE request to this resource to delete this workflow job.\n\n\n\n\n\n\n\n\n\n\n\n> _New in Ansible Tower 3.1.0_",
"renders": [
"application/json",
"text/html"
],
"parses": [
"application/json"
],
"actions": {
"GET": {
"id": {
"type": "integer",
"label": "ID",
"help_text": "Database ID for this workflow job."
},
"type": {
"type": "choice",
"label": "Type",
"help_text": "Data type for this workflow job.",
"choices": [
[
"workflow_job",
"Workflow Job"
]
]
},
"url": {
"type": "string",
"label": "Url",
"help_text": "URL for this workflow job."
},
"related": {
"type": "object",
"label": "Related",
"help_text": "Data structure with URLs of related resources."
},
"summary_fields": {
"type": "object",
"label": "Summary fields",
"help_text": "Data structure with name/description for related resources."
},
"created": {
"type": "datetime",
"label": "Created",
"help_text": "Timestamp when this workflow job was created."
},
"modified": {
"type": "datetime",
"label": "Modified",
"help_text": "Timestamp when this workflow job was last modified."
},
"name": {
"type": "string",
"label": "Name",
"help_text": "Name of this workflow job."
},
"description": {
"type": "string",
"label": "Description",
"help_text": "Optional description of this workflow job."
},
"unified_job_template": {
"type": "field",
"label": "unified job template"
},
"launch_type": {
"type": "choice",
"label": "Launch type",
"choices": [
[
"manual",
"Manual"
],
[
"relaunch",
"Relaunch"
],
[
"callback",
"Callback"
],
[
"scheduled",
"Scheduled"
],
[
"dependency",
"Dependency"
],
[
"workflow",
"Workflow"
],
[
"sync",
"Sync"
]
]
},
"status": {
"type": "choice",
"label": "Status",
"choices": [
[
"new",
"New"
],
[
"pending",
"Pending"
],
[
"waiting",
"Waiting"
],
[
"running",
"Running"
],
[
"successful",
"Successful"
],
[
"failed",
"Failed"
],
[
"error",
"Error"
],
[
"canceled",
"Canceled"
]
]
},
"failed": {
"type": "boolean",
"label": "Failed"
},
"started": {
"type": "datetime",
"label": "Started",
"help_text": "The date and time the job was queued for starting."
},
"finished": {
"type": "datetime",
"label": "Finished",
"help_text": "The date and time the job finished execution."
},
"elapsed": {
"type": "decimal",
"label": "Elapsed",
"help_text": "Elapsed time in seconds that the job ran."
},
"job_args": {
"type": "string",
"label": "Job args"
},
"job_cwd": {
"type": "string",
"label": "Job cwd"
},
"job_env": {
"type": "field",
"label": "job_env"
},
"job_explanation": {
"type": "string",
"label": "Job explanation",
"help_text": "A status field to indicate the state of the job if it wasn't able to run and capture stdout"
},
"result_stdout": {
"type": "field",
"label": "Result stdout"
},
"execution_node": {
"type": "string",
"label": "Execution node",
"help_text": "The Tower node the job executed on."
},
"result_traceback": {
"type": "string",
"label": "Result traceback"
},
"workflow_job_template": {
"type": "field",
"label": "Workflow job template"
},
"extra_vars": {
"type": "string",
"label": "Extra vars"
}
}
},
"added_in_version": "3.1.0",
"types": [
"workflow_job"
]
}

View File

@ -0,0 +1,136 @@
'use strict';
import moment from 'moment';
import workflow_job_options_json from './data/workflow_job_options.js';
import workflow_job_json from './data/workflow_job.js';
describe('Controller: workflowResults', () => {
let $controller;
let workflowResults;
let $rootScope;
let ParseVariableString;
let workflowResultsService;
let $interval;
let treeData = {
data: {
children: []
}
};
beforeEach(angular.mock.module('VariablesHelper'));
beforeEach(angular.mock.module('workflowResults', ($provide) => {
['PromptDialog', 'Prompt', 'Wait', 'Rest', '$state', 'ProcessErrors',
'InitiatePlaybookRun', 'jobLabels', 'workflowNodes', 'count',
].forEach((item) => {
$provide.value(item, {});
});
$provide.value('$stateExtender', { addState: jasmine.createSpy('addState'), });
$provide.value('moment', moment);
$provide.value('workflowData', workflow_job_json);
$provide.value('workflowDataOptions', workflow_job_options_json);
$provide.value('ParseTypeChange', function() {});
$provide.value('i18n', { '_': (a) => { return a; } });
$provide.provider('$stateProvider', { '$get': function() { return function() {} } });
$provide.service('WorkflowService', function($q) {
return {
buildTree: function() {
var deferred = $q.defer();
deferred.resolve(treeData);
return deferred.promise;
}
}
});
}));
beforeEach(angular.mock.inject(function(_$controller_, _$rootScope_, _ParseVariableString_, _workflowResultsService_, _$interval_){
$controller = _$controller_;
$rootScope = _$rootScope_;
ParseVariableString = _ParseVariableString_;
workflowResultsService = _workflowResultsService_;
$interval = _$interval_;
}));
describe('elapsed timer', () => {
let scope;
beforeEach(() => {
scope = $rootScope.$new();
spyOn(workflowResultsService, 'createOneSecondTimer').and.callThrough();
spyOn(workflowResultsService, 'destroyTimer').and.callThrough();
});
function jobWaitingWorkflowResultsControllerFixture(started, status) {
workflow_job_json.started = started;
workflow_job_json.status = status;
workflowResults = $controller('workflowResultsController', {
$scope: scope,
$rootScope: $rootScope,
});
}
describe('init()', () => {
describe('job running', () => {
beforeEach(() => {
jobWaitingWorkflowResultsControllerFixture(moment(), 'running');
});
// Note: Ensuring the outside service method is called to create a timer may
// be overkill. Especially since we validate the side effect in the next test.
it('should call to start timer on load when job is already running', () => {
expect(workflowResultsService.createOneSecondTimer).toHaveBeenCalled();
expect(workflowResultsService.createOneSecondTimer.calls.argsFor(0)[0]).toBe(workflow_job_json.started);
});
it('should set update scope var with elapsed time', () => {
$interval.flush(10 * 1000);
// TODO: mock moment() so when we fast-forward time with $interval
// the system clocks seems to fast forward too.
//expect(scope.workflow.elapsed).toBe(10);
});
it('should call to destroy timer on destroy', () => {
scope.$destroy();
expect(workflowResultsService.destroyTimer).toHaveBeenCalled();
expect(workflowResultsService.destroyTimer.calls.argsFor(0)[0]).not.toBe(null);
});
});
describe('job waiting', () => {
beforeEach(() => {
jobWaitingWorkflowResultsControllerFixture(null, 'waiting');
});
it('should not start elapsed timer', () => {
expect(workflowResultsService.createOneSecondTimer).not.toHaveBeenCalled();
});
});
describe('job finished', () => {
beforeEach(() => {
jobWaitingWorkflowResultsControllerFixture(moment(), 'successful');
});
it('should start elapsed timer', () => {
expect(workflowResultsService.createOneSecondTimer).not.toHaveBeenCalled();
});
});
});
describe('job transitions to running', () => {
beforeEach(() => {
jobWaitingWorkflowResultsControllerFixture(null, 'waiting');
$rootScope.$broadcast('ws-jobs', { unified_job_id: workflow_job_json.id, status: "running" });
});
it('should start elapsed timer', () => {
expect(scope.workflow.status).toBe("running");
expect(workflowResultsService.createOneSecondTimer).toHaveBeenCalled();
});
});
});
});

View File

@ -0,0 +1,59 @@
'use strict';
import moment from 'moment';
describe('workflowResultsService', () => {
let workflowResultsService;
let $interval;
beforeEach(angular.mock.module('workflowResults', ($provide) => {
['PromptDialog', 'Prompt', 'Wait', 'Rest', 'ProcessErrors', 'InitiatePlaybookRun', '$state'].forEach(function(item) {
$provide.value(item, {});
});
$provide.value('$stateExtender', { addState: jasmine.createSpy('addState'), });
$provide.value('moment', moment);
}));
beforeEach(angular.mock.inject((_workflowResultsService_, _$interval_) => {
workflowResultsService = _workflowResultsService_;
$interval = _$interval_;
}));
describe('createOneSecondTimer()', () => {
it('should create a timer that runs every second, incremented by a second', (done) => {
let ticks = 0;
let ticks_expected = 10;
workflowResultsService.createOneSecondTimer(moment(), function(time) {
ticks += 1;
if (ticks >= ticks_expected) {
expect(ticks).toBe(ticks_expected);
// TODO: should verify time is 10 but this requires mocking moment()
// because we "artificially" accelerate time.
done();
}
});
$interval.flush(ticks_expected * 1000);
});
});
describe('destroyTimer()', () => {
beforeEach(() => {
$interval.cancel = jasmine.createSpy('cancel');
});
it('should not destroy null timer', () => {
workflowResultsService.destroyTimer(null);
expect($interval.cancel).not.toHaveBeenCalled();
});
it('should destroy passed in timer', () => {
let timer = jasmine.createSpy('timer');
workflowResultsService.destroyTimer(timer);
expect($interval.cancel).toHaveBeenCalledWith(timer);
});
});
});