diff --git a/awx/ui/client/src/controllers/Jobs.js b/awx/ui/client/src/controllers/Jobs.js index 54187896df..dfa9cf1eec 100644 --- a/awx/ui/client/src/controllers/Jobs.js +++ b/awx/ui/client/src/controllers/Jobs.js @@ -84,6 +84,9 @@ export function JobsListController($state, $rootScope, $log, $scope, $compile, $ case 'inventory_update': goToJobDetails('inventorySyncStdout'); break; + case 'workflow_job': + goToJobDetails('workflowResults'); + break; } }; diff --git a/awx/ui/client/src/workflow-results/main.js b/awx/ui/client/src/workflow-results/main.js new file mode 100644 index 0000000000..eefa57c2dc --- /dev/null +++ b/awx/ui/client/src/workflow-results/main.js @@ -0,0 +1,14 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + + +import route from './job-results.route.js'; + +export default + angular.module('workflowResults', []) + .run(['$stateExtender', function($stateExtender) { + $stateExtender.addState(route); + }]); diff --git a/awx/ui/client/src/workflow-results/workflow-results.block.less b/awx/ui/client/src/workflow-results/workflow-results.block.less new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/ui/client/src/workflow-results/workflow-results.controller.js b/awx/ui/client/src/workflow-results/workflow-results.controller.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/awx/ui/client/src/workflow-results/workflow-results.partial.html b/awx/ui/client/src/workflow-results/workflow-results.partial.html new file mode 100644 index 0000000000..343c815c08 --- /dev/null +++ b/awx/ui/client/src/workflow-results/workflow-results.partial.html @@ -0,0 +1,522 @@ +
+
+
+ + +
+
+ + +
+
+ RESULTS +
+ + +
+ + + + + + + + + +
+
+ + +
+ + +
+ +
+ {{ job.started | longDate }} +
+
+ + +
+ +
+ {{ (job.finished | + longDate) || "Not Finished" }} +
+
+ + + + + +
+ +
+ {{ type_label }} +
+
+ + + + + + + + + + + +
+ +
+ {{ job.playbook }} +
+
+ + +
+ + +
+ + + + + + + + +
+ +
+ {{ job.forks }} +
+
+ + +
+ +
+ {{ job.limit }} +
+
+ + +
+ +
+ {{ verbosity_label }} +
+
+ + +
+ +
+ {{ job.job_tags }} +
+
+ + +
+ +
+ {{ job.skip_tags }} +
+
+ + +
+ + +
+ + +
+ +
+
+
+
+ {{ label }} +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ + +
+
+ + +
+
+ + + {{ job.name }} +
+ + +
+ +
+ Plays +
+ + {{ playCount || 0}} + + + +
+ Tasks +
+ + {{ taskCount || 0}} + + + +
+ Hosts +
+ + {{ hostCount || 0}} + + + +
+ Elapsed +
+ + {{ job.elapsed * 1000 | duration: "hh:mm:ss" }} + +
+ + +
+ + + + + + + + + +
+
+ + +
+ +
+
+
diff --git a/awx/ui/client/src/workflow-results/workflow-results.route.js b/awx/ui/client/src/workflow-results/workflow-results.route.js new file mode 100644 index 0000000000..dc10054c9e --- /dev/null +++ b/awx/ui/client/src/workflow-results/workflow-results.route.js @@ -0,0 +1,153 @@ +/************************************************* + * Copyright (c) 2016 Ansible, Inc. + * + * All Rights Reserved + *************************************************/ + +import {templateUrl} from '../shared/template-url/template-url.factory'; + +import workflowResultsController from './workflow-results.controller'; + +export default { + name: 'workflowResults', + url: '/jobs/:id', + ncyBreadcrumb: { + parent: 'jobs', + label: '{{ job.id }} - {{ job.name }}' + }, + data: { + socket: { + "groups":{ + "jobs": ["status_changed", "summary"], + "job_events": [] + } + } + }, + templateUrl: templateUrl('workflow-results/workflow-results'), + controller: workflowResultsController + // resolve: { + // // the GET for the particular job + // jobData: ['Rest', 'GetBasePath', '$stateParams', '$q', '$state', 'Alert', function(Rest, GetBasePath, $stateParams, $q, $state, Alert) { + // Rest.setUrl(GetBasePath('jobs') + $stateParams.id); + // var val = $q.defer(); + // Rest.get() + // .then(function(data) { + // val.resolve(data.data); + // }, function(data) { + // val.reject(data); + // + // if (data.status === 404) { + // Alert('Job Not Found', 'Cannot find job.', 'alert-info'); + // } else if (data.status === 403) { + // Alert('Insufficient Permissions', 'You do not have permission to view this job.', 'alert-info'); + // } + // + // $state.go('jobs'); + // }); + // return val.promise; + // }], + // // after the GET for the job, this helps us keep the status bar from + // // flashing as rest data comes in. If the job is finished and + // // there's a playbook_on_stats event, go ahead and resolve the count + // // so you don't get that flashing! + // count: ['jobData', 'jobResultsService', 'Rest', '$q', function(jobData, jobResultsService, Rest, $q) { + // var defer = $q.defer(); + // if (jobData.finished) { + // // if the job is finished, grab the playbook_on_stats + // // role to get the final count + // Rest.setUrl(jobData.related.job_events + + // "?event=playbook_on_stats"); + // Rest.get() + // .success(function(data) { + // if(!data.results[0]){ + // defer.resolve({val: { + // ok: 0, + // skipped: 0, + // unreachable: 0, + // failures: 0, + // changed: 0 + // }, countFinished: false}); + // } + // else { + // defer.resolve({ + // val: jobResultsService + // .getCountsFromStatsEvent(data + // .results[0].event_data), + // countFinished: true}); + // } + // }) + // .error(function() { + // defer.resolve({val: { + // ok: 0, + // skipped: 0, + // unreachable: 0, + // failures: 0, + // changed: 0 + // }, countFinished: false}); + // }); + // } else { + // // job isn't finished so just send an empty count and read + // // from events + // defer.resolve({val: { + // ok: 0, + // skipped: 0, + // unreachable: 0, + // failures: 0, + // changed: 0 + // }, countFinished: false}); + // } + // return defer.promise; + // }], + // // GET for the particular jobs labels to be displayed in the + // // left-hand pane + // jobLabels: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) { + // var getNext = function(data, arr, resolve) { + // Rest.setUrl(data.next); + // Rest.get() + // .success(function (data) { + // if (data.next) { + // getNext(data, arr.concat(data.results), resolve); + // } else { + // resolve.resolve(arr.concat(data.results) + // .map(val => val.name)); + // } + // }); + // }; + // + // var seeMoreResolve = $q.defer(); + // + // Rest.setUrl(GetBasePath('jobs') + $stateParams.id + '/labels/'); + // Rest.get() + // .success(function(data) { + // if (data.next) { + // getNext(data, data.results, seeMoreResolve); + // } else { + // seeMoreResolve.resolve(data.results + // .map(val => val.name)); + // } + // }); + // + // return seeMoreResolve.promise; + // }], + // // OPTIONS request for the job. Used to make things like the + // // verbosity data in the left-hand pane prettier than just an + // // integer + // jobDataOptions: ['Rest', 'GetBasePath', '$stateParams', '$q', function(Rest, GetBasePath, $stateParams, $q) { + // Rest.setUrl(GetBasePath('jobs') + $stateParams.id); + // var val = $q.defer(); + // Rest.options() + // .then(function(data) { + // val.resolve(data.data); + // }, function(data) { + // val.reject(data); + // }); + // return val.promise; + // }], + // // This clears out the event queue, otherwise it'd be full of events + // // for previous job results the user had navigated to + // eventQueueInit: ['eventQueue', function(eventQueue) { + // eventQueue.initialize(); + // }] + // }, + // +};