mirror of
https://github.com/ansible/awx.git
synced 2026-03-28 06:15:04 -02:30
Merge pull request #1694 from jakemcdermott/job-results/remove-watch
job results - remove all watchers and move code into components
This commit is contained in:
@@ -2,7 +2,6 @@ const templateUrl = require('~features/output/details.partial.html');
|
|||||||
|
|
||||||
let $http;
|
let $http;
|
||||||
let $filter;
|
let $filter;
|
||||||
let $scope;
|
|
||||||
let $state;
|
let $state;
|
||||||
|
|
||||||
let error;
|
let error;
|
||||||
@@ -10,7 +9,6 @@ let parse;
|
|||||||
let prompt;
|
let prompt;
|
||||||
let resource;
|
let resource;
|
||||||
let strings;
|
let strings;
|
||||||
let status;
|
|
||||||
let wait;
|
let wait;
|
||||||
|
|
||||||
let vm;
|
let vm;
|
||||||
@@ -372,7 +370,7 @@ function getJobTagDetails () {
|
|||||||
let jobTags;
|
let jobTags;
|
||||||
|
|
||||||
if (tagString) {
|
if (tagString) {
|
||||||
jobTags = tagString.split(',');
|
jobTags = tagString.split(',').filter(tag => tag !== '');
|
||||||
} else {
|
} else {
|
||||||
jobTags = [];
|
jobTags = [];
|
||||||
}
|
}
|
||||||
@@ -384,7 +382,7 @@ function getJobTagDetails () {
|
|||||||
const label = 'Job Tags';
|
const label = 'Job Tags';
|
||||||
const more = false;
|
const more = false;
|
||||||
|
|
||||||
const value = jobTags.filter(tag => tag !== '').map($filter('sanitize'));
|
const value = jobTags.map($filter('sanitize'));
|
||||||
|
|
||||||
return { label, more, value };
|
return { label, more, value };
|
||||||
}
|
}
|
||||||
@@ -395,7 +393,7 @@ function getSkipTagDetails () {
|
|||||||
let skipTags;
|
let skipTags;
|
||||||
|
|
||||||
if (tagString) {
|
if (tagString) {
|
||||||
skipTags = tagString.split(',');
|
skipTags = tagString.split(',').filter(tag => tag !== '');
|
||||||
} else {
|
} else {
|
||||||
skipTags = [];
|
skipTags = [];
|
||||||
}
|
}
|
||||||
@@ -406,7 +404,7 @@ function getSkipTagDetails () {
|
|||||||
|
|
||||||
const label = 'Skip Tags';
|
const label = 'Skip Tags';
|
||||||
const more = false;
|
const more = false;
|
||||||
const value = skipTags.filter(tag => tag !== '').map($filter('sanitize'));
|
const value = skipTags.map($filter('sanitize'));
|
||||||
|
|
||||||
return { label, more, value };
|
return { label, more, value };
|
||||||
}
|
}
|
||||||
@@ -446,7 +444,7 @@ function createErrorHandler (path, action) {
|
|||||||
const hdr = strings.get('error.HEADER');
|
const hdr = strings.get('error.HEADER');
|
||||||
const msg = strings.get('error.CALL', { path, action, status: res.status });
|
const msg = strings.get('error.CALL', { path, action, status: res.status });
|
||||||
|
|
||||||
error($scope, res.data, res.status, null, { hdr, msg });
|
error(null, res.data, res.status, null, { hdr, msg });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,33 +544,33 @@ function deleteJob () {
|
|||||||
prompt({ hdr, resourceName, body, actionText, action });
|
prompt({ hdr, resourceName, body, actionText, action });
|
||||||
}
|
}
|
||||||
|
|
||||||
function AtJobDetailsController (
|
function JobDetailsController (
|
||||||
_$http_,
|
_$http_,
|
||||||
_$filter_,
|
_$filter_,
|
||||||
_$state_,
|
_$state_,
|
||||||
_error_,
|
_error_,
|
||||||
_prompt_,
|
_prompt_,
|
||||||
_strings_,
|
_strings_,
|
||||||
_status_,
|
|
||||||
_wait_,
|
_wait_,
|
||||||
_parse_,
|
_parse_,
|
||||||
|
{ subscribe },
|
||||||
) {
|
) {
|
||||||
vm = this || {};
|
vm = this || {};
|
||||||
|
|
||||||
$http = _$http_;
|
$http = _$http_;
|
||||||
$filter = _$filter_;
|
$filter = _$filter_;
|
||||||
$state = _$state_;
|
$state = _$state_;
|
||||||
|
|
||||||
error = _error_;
|
error = _error_;
|
||||||
|
|
||||||
parse = _parse_;
|
parse = _parse_;
|
||||||
prompt = _prompt_;
|
prompt = _prompt_;
|
||||||
strings = _strings_;
|
strings = _strings_;
|
||||||
status = _status_;
|
|
||||||
wait = _wait_;
|
wait = _wait_;
|
||||||
|
|
||||||
vm.init = _$scope_ => {
|
let unsubscribe;
|
||||||
$scope = _$scope_;
|
|
||||||
resource = $scope.resource; // eslint-disable-line prefer-destructuring
|
vm.$onInit = () => {
|
||||||
|
resource = this.resource; // eslint-disable-line prefer-destructuring
|
||||||
|
|
||||||
vm.status = getStatusDetails();
|
vm.status = getStatusDetails();
|
||||||
vm.started = getStartDetails();
|
vm.started = getStartDetails();
|
||||||
@@ -606,54 +604,42 @@ function AtJobDetailsController (
|
|||||||
|
|
||||||
vm.cancelJob = cancelJob;
|
vm.cancelJob = cancelJob;
|
||||||
vm.deleteJob = deleteJob;
|
vm.deleteJob = deleteJob;
|
||||||
vm.toggleLabels = toggleLabels;
|
|
||||||
vm.toggleJobTags = toggleJobTags;
|
vm.toggleJobTags = toggleJobTags;
|
||||||
vm.toggleSkipTags = toggleSkipTags;
|
vm.toggleSkipTags = toggleSkipTags;
|
||||||
|
vm.toggleLabels = toggleLabels;
|
||||||
|
|
||||||
const observe = (getter, transform, key) => {
|
unsubscribe = subscribe(({ status, started, finished, scm }) => {
|
||||||
$scope.$watch(getter, value => { vm[key] = transform(value); });
|
vm.started = getStartDetails(started);
|
||||||
};
|
vm.finished = getFinishDetails(finished);
|
||||||
|
vm.projectUpdate = getProjectUpdateDetails(scm.id);
|
||||||
observe(status.getStarted, getStartDetails, 'started');
|
vm.projectStatus = getProjectStatusDetails(scm.status);
|
||||||
observe(status.getFinished, getFinishDetails, 'finished');
|
vm.status = getStatusDetails(status);
|
||||||
observe(status.getProjectUpdateId, getProjectUpdateDetails, 'projectUpdate');
|
vm.job.status = status;
|
||||||
observe(status.getProjectStatus, getProjectStatusDetails, 'projectStatus');
|
|
||||||
|
|
||||||
$scope.$watch(status.getJobStatus, jobStatus => {
|
|
||||||
vm.status = getStatusDetails(jobStatus);
|
|
||||||
vm.job.status = jobStatus;
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
vm.$onDestroy = () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
AtJobDetailsController.$inject = [
|
JobDetailsController.$inject = [
|
||||||
'$http',
|
'$http',
|
||||||
'$filter',
|
'$filter',
|
||||||
'$state',
|
'$state',
|
||||||
'ProcessErrors',
|
'ProcessErrors',
|
||||||
'Prompt',
|
'Prompt',
|
||||||
'JobStrings',
|
'JobStrings',
|
||||||
'JobStatusService',
|
|
||||||
'Wait',
|
'Wait',
|
||||||
'ParseVariableString',
|
'ParseVariableString',
|
||||||
|
'JobStatusService',
|
||||||
];
|
];
|
||||||
|
|
||||||
function atJobDetailsLink (scope, el, attrs, controllers) {
|
export default {
|
||||||
const [atDetailsController] = controllers;
|
templateUrl,
|
||||||
|
controller: JobDetailsController,
|
||||||
atDetailsController.init(scope);
|
controllerAs: 'vm',
|
||||||
}
|
bindings: {
|
||||||
|
resource: '<'
|
||||||
function atJobDetails () {
|
},
|
||||||
return {
|
};
|
||||||
templateUrl,
|
|
||||||
restrict: 'E',
|
|
||||||
require: ['atJobDetails'],
|
|
||||||
controllerAs: 'vm',
|
|
||||||
link: atJobDetailsLink,
|
|
||||||
controller: AtJobDetailsController,
|
|
||||||
scope: { resource: '=', },
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default atJobDetails;
|
|
||||||
@@ -38,9 +38,8 @@ function JobsIndexController (
|
|||||||
vm.clear = devClear;
|
vm.clear = devClear;
|
||||||
|
|
||||||
// Expand/collapse
|
// Expand/collapse
|
||||||
// vm.toggle = toggle;
|
vm.expanded = false;
|
||||||
// vm.expand = expand;
|
vm.toggleExpanded = toggleExpanded;
|
||||||
vm.isExpanded = true;
|
|
||||||
|
|
||||||
// Panel
|
// Panel
|
||||||
vm.resource = resource;
|
vm.resource = resource;
|
||||||
@@ -55,10 +54,6 @@ function JobsIndexController (
|
|||||||
up: scrollPageUp
|
up: scrollPageUp
|
||||||
};
|
};
|
||||||
|
|
||||||
vm.fullscreen = {
|
|
||||||
isFullscreen: false
|
|
||||||
};
|
|
||||||
|
|
||||||
render.requestAnimationFrame(() => init());
|
render.requestAnimationFrame(() => init());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,13 +91,14 @@ function init () {
|
|||||||
},
|
},
|
||||||
onStop () {
|
onStop () {
|
||||||
status.updateStats();
|
status.updateStats();
|
||||||
|
status.dispatch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$scope.$on(resource.ws.events, handleJobEvent);
|
$scope.$on(resource.ws.events, handleJobEvent);
|
||||||
$scope.$on(resource.ws.status, handleStatusEvent);
|
$scope.$on(resource.ws.status, handleStatusEvent);
|
||||||
|
|
||||||
if (!status.isRunning()) {
|
if (!status.state.running) {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,9 +277,9 @@ function scrollIsAtRest (isAtRest) {
|
|||||||
vm.scroll.showBackToTop = !isAtRest;
|
vm.scroll.showBackToTop = !isAtRest;
|
||||||
}
|
}
|
||||||
|
|
||||||
// function expand () {
|
function toggleExpanded () {
|
||||||
// vm.toggle(parent, true);
|
vm.expanded = !vm.expanded;
|
||||||
// }
|
}
|
||||||
|
|
||||||
// function showHostDetails (id) {
|
// function showHostDetails (id) {
|
||||||
// jobEvent.request('get', id)
|
// jobEvent.request('get', id)
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ import RenderService from '~features/output/render.service';
|
|||||||
import ScrollService from '~features/output/scroll.service';
|
import ScrollService from '~features/output/scroll.service';
|
||||||
import EngineService from '~features/output/engine.service';
|
import EngineService from '~features/output/engine.service';
|
||||||
import StatusService from '~features/output/status.service';
|
import StatusService from '~features/output/status.service';
|
||||||
|
import MessageService from '~features/output/message.service';
|
||||||
import LegacyRedirect from '~features/output/legacy.route';
|
import LegacyRedirect from '~features/output/legacy.route';
|
||||||
|
|
||||||
import DetailsDirective from '~features/output/details.directive';
|
import DetailsComponent from '~features/output/details.component';
|
||||||
import SearchDirective from '~features/output/search.directive';
|
import SearchComponent from '~features/output/search.component';
|
||||||
import StatsDirective from '~features/output/stats.directive';
|
import StatsComponent from '~features/output/stats.component';
|
||||||
import HostEvent from './host-event/index';
|
import HostEvent from './host-event/index';
|
||||||
|
|
||||||
const Template = require('~features/output/index.view.html');
|
const Template = require('~features/output/index.view.html');
|
||||||
@@ -175,7 +176,7 @@ function JobsRun ($stateRegistry, strings) {
|
|||||||
templateUrl: Template,
|
templateUrl: Template,
|
||||||
controller: Controller,
|
controller: Controller,
|
||||||
controllerAs: 'vm'
|
controllerAs: 'vm'
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
webSocketConnection: [
|
webSocketConnection: [
|
||||||
@@ -221,9 +222,10 @@ angular
|
|||||||
.service('JobRenderService', RenderService)
|
.service('JobRenderService', RenderService)
|
||||||
.service('JobEventEngine', EngineService)
|
.service('JobEventEngine', EngineService)
|
||||||
.service('JobStatusService', StatusService)
|
.service('JobStatusService', StatusService)
|
||||||
.directive('atJobDetails', DetailsDirective)
|
.service('JobMessageService', MessageService)
|
||||||
.directive('atJobSearch', SearchDirective)
|
.component('atJobSearch', SearchComponent)
|
||||||
.directive('atJobStats', StatsDirective)
|
.component('atJobStats', StatsComponent)
|
||||||
|
.component('atJobDetails', DetailsComponent)
|
||||||
.run(JobsRun)
|
.run(JobsRun)
|
||||||
.run(LegacyRedirect);
|
.run(LegacyRedirect);
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
<div ui-view></div>
|
<div ui-view></div>
|
||||||
<div class="JobResults-container">
|
<div class="JobResults-container">
|
||||||
<at-panel ng-show="!vm.fullscreen.isFullscreen">
|
<at-panel ng-show="!vm.expanded">
|
||||||
<at-job-details resource="vm.resource"></at-job-details>
|
<at-job-details
|
||||||
|
resource="vm.resource">
|
||||||
|
</at-job-details>
|
||||||
</at-panel>
|
</at-panel>
|
||||||
|
|
||||||
<at-panel class="at-Stdout" ng-class="{'at-Stdout--fullscreen': vm.fullscreen.isFullscreen}">
|
<at-panel class="at-Stdout" ng-class="{'at-Stdout--fullscreen': vm.expanded}">
|
||||||
<div class="at-Panel-headingTitle">
|
<div class="at-Panel-headingTitle">
|
||||||
{{ vm.title }}
|
{{ vm.title }}
|
||||||
</div>
|
</div>
|
||||||
<at-job-stats
|
<at-job-stats
|
||||||
resource="vm.resource"
|
resource="vm.resource"
|
||||||
fullscreen="vm.fullscreen">
|
expanded="vm.expanded">
|
||||||
</at-job-stats>
|
</at-job-stats>
|
||||||
<at-job-search></at-job-search>
|
<at-job-search></at-job-search>
|
||||||
|
|
||||||
<div class="at-Stdout-menuTop">
|
<div class="at-Stdout-menuTop">
|
||||||
<div class="pull-left" ng-click="vm.expand()">
|
<div class="pull-left" ng-click="vm.toggleExpand()">
|
||||||
<i class="at-Stdout-menuIcon fa"
|
<i class="at-Stdout-menuIcon fa"
|
||||||
ng-class="{ 'fa-minus': vm.isExpanded, 'fa-plus': !vm.isExpanded }"></i>
|
ng-class="{ 'fa-minus': vm.expanded, 'fa-plus': !vm.expanded }"></i>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="pull-right" ng-click="vm.scroll.end()">
|
<div class="pull-right" ng-click="vm.scroll.end()">
|
||||||
|
|||||||
41
awx/ui/client/features/output/message.service.js
Normal file
41
awx/ui/client/features/output/message.service.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
function MessageService () {
|
||||||
|
const listeners = {};
|
||||||
|
const registry = {};
|
||||||
|
|
||||||
|
this.subscribe = (key, listener) => {
|
||||||
|
registry[key] = registry[key] || 0;
|
||||||
|
|
||||||
|
listeners[key] = listeners[key] || {};
|
||||||
|
listeners[key][registry[key]] = listener;
|
||||||
|
|
||||||
|
const unsubscribe = this.createCallback(key, registry[key]);
|
||||||
|
|
||||||
|
registry[key]++;
|
||||||
|
|
||||||
|
return unsubscribe;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.dispatch = (key, data) => {
|
||||||
|
if (!listeners[key]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const indices = Object.keys(listeners[key]);
|
||||||
|
|
||||||
|
for (let i = 0; i < indices.length; i++) {
|
||||||
|
listeners[key][indices[i]](data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.createCallback = (key, index) => {
|
||||||
|
const callback = () => {
|
||||||
|
if (listeners[key]) {
|
||||||
|
delete listeners[key][index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return callback;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MessageService;
|
||||||
@@ -8,7 +8,6 @@ const PLACEHOLDER_RUNNING = 'CANNOT SEARCH RUNNING JOB';
|
|||||||
const PLACEHOLDER_DEFAULT = 'SEARCH';
|
const PLACEHOLDER_DEFAULT = 'SEARCH';
|
||||||
|
|
||||||
let $state;
|
let $state;
|
||||||
let status;
|
|
||||||
let qs;
|
let qs;
|
||||||
|
|
||||||
let vm;
|
let vm;
|
||||||
@@ -65,15 +64,8 @@ function clearSearch () {
|
|||||||
$state.transitionTo($state.current, $state.params, searchReloadOptions);
|
$state.transitionTo($state.current, $state.params, searchReloadOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
function atJobSearchLink (scope, el, attrs, controllers) {
|
function JobSearchController (_$state_, _qs_, { subscribe }) {
|
||||||
const [atJobSearchController] = controllers;
|
|
||||||
|
|
||||||
atJobSearchController.init(scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
function AtJobSearchController (_$state_, _status_, _qs_) {
|
|
||||||
$state = _$state_;
|
$state = _$state_;
|
||||||
status = _status_;
|
|
||||||
qs = _qs_;
|
qs = _qs_;
|
||||||
|
|
||||||
vm = this || {};
|
vm = this || {};
|
||||||
@@ -91,39 +83,33 @@ function AtJobSearchController (_$state_, _status_, _qs_) {
|
|||||||
vm.removeSearchTag = removeSearchTag;
|
vm.removeSearchTag = removeSearchTag;
|
||||||
vm.submitSearch = submitSearch;
|
vm.submitSearch = submitSearch;
|
||||||
|
|
||||||
vm.init = scope => {
|
let unsubscribe;
|
||||||
vm.examples = scope.examples || searchKeyExamples;
|
|
||||||
vm.fields = scope.fields || searchKeyFields;
|
|
||||||
vm.placeholder = PLACEHOLDER_DEFAULT;
|
|
||||||
vm.relatedFields = scope.relatedFields || [];
|
|
||||||
|
|
||||||
scope.$watch(status.isRunning, value => {
|
vm.$onInit = () => {
|
||||||
vm.disabled = value;
|
vm.examples = searchKeyExamples;
|
||||||
vm.placeholder = value ? PLACEHOLDER_RUNNING : PLACEHOLDER_DEFAULT;
|
vm.fields = searchKeyFields;
|
||||||
|
vm.placeholder = PLACEHOLDER_DEFAULT;
|
||||||
|
vm.relatedFields = [];
|
||||||
|
|
||||||
|
unsubscribe = subscribe(({ running }) => {
|
||||||
|
vm.disabled = running;
|
||||||
|
vm.placeholder = running ? PLACEHOLDER_RUNNING : PLACEHOLDER_DEFAULT;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
|
||||||
AtJobSearchController.$inject = [
|
vm.$onDestroy = () => {
|
||||||
'$state',
|
unsubscribe();
|
||||||
'JobStatusService',
|
|
||||||
'QuerySet',
|
|
||||||
];
|
|
||||||
|
|
||||||
function atJobSearch () {
|
|
||||||
return {
|
|
||||||
templateUrl,
|
|
||||||
restrict: 'E',
|
|
||||||
require: ['atJobSearch'],
|
|
||||||
controllerAs: 'vm',
|
|
||||||
link: atJobSearchLink,
|
|
||||||
controller: AtJobSearchController,
|
|
||||||
scope: {
|
|
||||||
examples: '=',
|
|
||||||
fields: '=',
|
|
||||||
relatedFields: '=',
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default atJobSearch;
|
JobSearchController.$inject = [
|
||||||
|
'$state',
|
||||||
|
'QuerySet',
|
||||||
|
'JobStatusService',
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
templateUrl,
|
||||||
|
controller: JobSearchController,
|
||||||
|
controllerAs: 'vm',
|
||||||
|
};
|
||||||
74
awx/ui/client/features/output/stats.component.js
Normal file
74
awx/ui/client/features/output/stats.component.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
const templateUrl = require('~features/output/stats.partial.html');
|
||||||
|
|
||||||
|
let vm;
|
||||||
|
|
||||||
|
function createStatsBarTooltip (key, count) {
|
||||||
|
const label = `<span class='HostStatusBar-tooltipLabel'>${key}</span>`;
|
||||||
|
const badge = `<span class='badge HostStatusBar-tooltipBadge HostStatusBar-tooltipBadge--${key}'>${count}</span>`;
|
||||||
|
|
||||||
|
return `${label}${badge}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function JobStatsController (strings, { subscribe }) {
|
||||||
|
vm = this || {};
|
||||||
|
|
||||||
|
let unsubscribe;
|
||||||
|
|
||||||
|
vm.tooltips = {
|
||||||
|
running: strings.get('status.RUNNING'),
|
||||||
|
unavailable: strings.get('status.UNAVAILABLE'),
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.$onInit = () => {
|
||||||
|
vm.download = vm.resource.model.get('related.stdout');
|
||||||
|
vm.toggleStdoutFullscreenTooltip = strings.get('expandCollapse.EXPAND');
|
||||||
|
|
||||||
|
unsubscribe = subscribe(({ running, elapsed, counts, stats, hosts }) => {
|
||||||
|
vm.plays = counts.plays;
|
||||||
|
vm.tasks = counts.tasks;
|
||||||
|
vm.hosts = counts.hosts;
|
||||||
|
vm.elapsed = elapsed;
|
||||||
|
vm.running = running;
|
||||||
|
vm.setHostStatusCounts(stats, hosts);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.$onDestroy = () => {
|
||||||
|
unsubscribe();
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.setHostStatusCounts = (stats, counts) => {
|
||||||
|
Object.keys(counts).forEach(key => {
|
||||||
|
const count = counts[key];
|
||||||
|
const statusBarElement = $(`.HostStatusBar-${key}`);
|
||||||
|
|
||||||
|
statusBarElement.css('flex', `${count} 0 auto`);
|
||||||
|
|
||||||
|
vm.tooltips[key] = createStatsBarTooltip(key, count);
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.statsAreAvailable = stats;
|
||||||
|
};
|
||||||
|
|
||||||
|
vm.toggleExpanded = () => {
|
||||||
|
vm.expanded = !vm.expanded;
|
||||||
|
vm.toggleStdoutFullscreenTooltip = vm.expanded ?
|
||||||
|
strings.get('expandCollapse.COLLAPSE') :
|
||||||
|
strings.get('expandCollapse.EXPAND');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
JobStatsController.$inject = [
|
||||||
|
'JobStrings',
|
||||||
|
'JobStatusService',
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
templateUrl,
|
||||||
|
controller: JobStatsController,
|
||||||
|
controllerAs: 'vm',
|
||||||
|
bindings: {
|
||||||
|
resource: '<',
|
||||||
|
expanded: '=',
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
const templateUrl = require('~features/output/stats.partial.html');
|
|
||||||
|
|
||||||
let status;
|
|
||||||
let strings;
|
|
||||||
|
|
||||||
function createStatsBarTooltip (key, count) {
|
|
||||||
const label = `<span class='HostStatusBar-tooltipLabel'>${key}</span>`;
|
|
||||||
const badge = `<span class='badge HostStatusBar-tooltipBadge HostStatusBar-tooltipBadge--${key}'>${count}</span>`;
|
|
||||||
|
|
||||||
return `${label}${badge}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function atJobStatsLink (scope, el, attrs, controllers) {
|
|
||||||
const [atJobStatsController] = controllers;
|
|
||||||
|
|
||||||
atJobStatsController.init(scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
function AtJobStatsController (_strings_, _status_) {
|
|
||||||
status = _status_;
|
|
||||||
strings = _strings_;
|
|
||||||
|
|
||||||
const vm = this || {};
|
|
||||||
|
|
||||||
vm.tooltips = {
|
|
||||||
running: strings.get('status.RUNNING'),
|
|
||||||
unavailable: strings.get('status.UNAVAILABLE'),
|
|
||||||
};
|
|
||||||
|
|
||||||
vm.init = scope => {
|
|
||||||
const { resource } = scope;
|
|
||||||
|
|
||||||
vm.fullscreen = scope.fullscreen;
|
|
||||||
|
|
||||||
vm.download = resource.model.get('related.stdout');
|
|
||||||
|
|
||||||
vm.toggleStdoutFullscreenTooltip = strings.get('expandCollapse.EXPAND');
|
|
||||||
|
|
||||||
vm.setHostStatusCounts(status.getHostStatusCounts());
|
|
||||||
|
|
||||||
scope.$watch(status.getPlayCount, value => { vm.plays = value; });
|
|
||||||
scope.$watch(status.getTaskCount, value => { vm.tasks = value; });
|
|
||||||
scope.$watch(status.getElapsed, value => { vm.elapsed = value; });
|
|
||||||
scope.$watch(status.getHostCount, value => { vm.hosts = value; });
|
|
||||||
scope.$watch(status.isRunning, value => { vm.running = value; });
|
|
||||||
|
|
||||||
scope.$watchCollection(status.getHostStatusCounts, vm.setHostStatusCounts);
|
|
||||||
};
|
|
||||||
|
|
||||||
vm.setHostStatusCounts = counts => {
|
|
||||||
Object.keys(counts).forEach(key => {
|
|
||||||
const count = counts[key];
|
|
||||||
const statusBarElement = $(`.HostStatusBar-${key}`);
|
|
||||||
|
|
||||||
statusBarElement.css('flex', `${count} 0 auto`);
|
|
||||||
|
|
||||||
vm.tooltips[key] = createStatsBarTooltip(key, count);
|
|
||||||
});
|
|
||||||
|
|
||||||
vm.statsAreAvailable = Boolean(status.getStatsEvent());
|
|
||||||
};
|
|
||||||
|
|
||||||
vm.toggleFullscreen = () => {
|
|
||||||
vm.fullscreen.isFullscreen = !vm.fullscreen.isFullscreen;
|
|
||||||
vm.toggleStdoutFullscreenTooltip = vm.fullscreen.isFullscreen ?
|
|
||||||
strings.get('expandCollapse.COLLAPSE') :
|
|
||||||
strings.get('expandCollapse.EXPAND');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function atJobStats () {
|
|
||||||
return {
|
|
||||||
templateUrl,
|
|
||||||
restrict: 'E',
|
|
||||||
require: ['atJobStats'],
|
|
||||||
controllerAs: 'vm',
|
|
||||||
link: atJobStatsLink,
|
|
||||||
controller: [
|
|
||||||
'JobStrings',
|
|
||||||
'JobStatusService',
|
|
||||||
'$scope',
|
|
||||||
AtJobStatsController
|
|
||||||
],
|
|
||||||
scope: {
|
|
||||||
resource: '=',
|
|
||||||
fullscreen: '='
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default atJobStats;
|
|
||||||
@@ -31,8 +31,8 @@
|
|||||||
aw-tool-tip="{{ vm.toggleStdoutFullscreenTooltip }}"
|
aw-tool-tip="{{ vm.toggleStdoutFullscreenTooltip }}"
|
||||||
data-tip-watch="vm.toggleStdoutFullscreenTooltip"
|
data-tip-watch="vm.toggleStdoutFullscreenTooltip"
|
||||||
data-placement="top"
|
data-placement="top"
|
||||||
ng-class="{'at-Input-button--active': vm.fullscreen.isFullscreen}"
|
ng-class="{'at-Input-button--active': vm.expanded}"
|
||||||
ng-click="vm.toggleFullscreen()">
|
ng-click="vm.toggleExpanded()">
|
||||||
<i class="fa fa-arrows-alt"></i>
|
<i class="fa fa-arrows-alt"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,34 +6,46 @@ const TASK_START = 'playbook_on_task_start';
|
|||||||
const HOST_STATUS_KEYS = ['dark', 'failures', 'changed', 'ok', 'skipped'];
|
const HOST_STATUS_KEYS = ['dark', 'failures', 'changed', 'ok', 'skipped'];
|
||||||
const FINISHED = ['successful', 'failed', 'error'];
|
const FINISHED = ['successful', 'failed', 'error'];
|
||||||
|
|
||||||
let moment;
|
function JobStatusService (moment, message) {
|
||||||
|
this.dispatch = () => message.dispatch('status', this.state);
|
||||||
function JobStatusService (_moment_) {
|
this.subscribe = listener => message.subscribe('status', listener);
|
||||||
moment = _moment_;
|
|
||||||
|
|
||||||
this.init = ({ resource }) => {
|
this.init = ({ resource }) => {
|
||||||
|
const { model } = resource;
|
||||||
|
|
||||||
|
this.created = model.get('created');
|
||||||
|
this.job = model.get('id');
|
||||||
|
this.jobType = model.get('type');
|
||||||
|
this.project = model.get('project');
|
||||||
|
|
||||||
|
this.active = false;
|
||||||
|
this.latestTime = null;
|
||||||
this.counter = -1;
|
this.counter = -1;
|
||||||
|
|
||||||
this.created = resource.model.get('created');
|
this.state = {
|
||||||
this.job = resource.model.get('id');
|
running: false,
|
||||||
this.jobType = resource.model.get('type');
|
stats: false,
|
||||||
this.project = resource.model.get('project');
|
counts: {
|
||||||
this.elapsed = resource.model.get('elapsed');
|
plays: null,
|
||||||
this.started = resource.model.get('started');
|
tasks: null,
|
||||||
this.finished = resource.model.get('finished');
|
hosts: null,
|
||||||
this.jobStatus = resource.model.get('status');
|
},
|
||||||
this.projectStatus = resource.model.get('summary_fields.project_update.status');
|
hosts: {},
|
||||||
this.projectUpdateId = resource.model.get('summary_fields.project_update.id');
|
status: model.get('status'),
|
||||||
|
elapsed: model.get('elapsed'),
|
||||||
|
started: model.get('started'),
|
||||||
|
finished: model.get('finished'),
|
||||||
|
scm: {
|
||||||
|
id: model.get('summary_fields.project_update.id'),
|
||||||
|
status: model.get('summary_fields.project_update.status')
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
this.latestTime = null;
|
this.setStatsEvent(resource.stats);
|
||||||
this.playCount = null;
|
|
||||||
this.taskCount = null;
|
|
||||||
this.hostCount = null;
|
|
||||||
this.active = false;
|
|
||||||
this.hostStatusCounts = {};
|
|
||||||
|
|
||||||
this.statsEvent = resource.stats;
|
|
||||||
this.updateStats();
|
this.updateStats();
|
||||||
|
this.updateRunningState();
|
||||||
|
|
||||||
|
this.dispatch();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.pushStatusEvent = data => {
|
this.pushStatusEvent = data => {
|
||||||
@@ -59,24 +71,46 @@ function JobStatusService (_moment_) {
|
|||||||
if (isLatest) {
|
if (isLatest) {
|
||||||
this.counter = data.counter;
|
this.counter = data.counter;
|
||||||
this.latestTime = data.created;
|
this.latestTime = data.created;
|
||||||
this.elapsed = moment(data.created).diff(this.created, 'seconds');
|
this.setElapsed(moment(data.created).diff(this.created, 'seconds'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.event === JOB_START) {
|
if (data.event === JOB_START) {
|
||||||
this.started = this.started || data.created;
|
this.setStarted(this.state.started || data.created);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.event === PLAY_START) {
|
if (data.event === PLAY_START) {
|
||||||
this.playCount++;
|
this.state.counts.plays++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.event === TASK_START) {
|
if (data.event === TASK_START) {
|
||||||
this.taskCount++;
|
this.state.counts.tasks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.event === JOB_END) {
|
if (data.event === JOB_END) {
|
||||||
this.statsEvent = data;
|
this.setStatsEvent(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.dispatch();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isExpectingStatsEvent = () => (this.jobType === 'job') ||
|
||||||
|
(this.jobType === 'project_update');
|
||||||
|
|
||||||
|
this.updateStats = () => {
|
||||||
|
this.updateHostCounts();
|
||||||
|
|
||||||
|
if (this.statsEvent) {
|
||||||
|
this.state.stats = true;
|
||||||
|
this.setFinished(this.statsEvent.created);
|
||||||
|
this.setJobStatus(this.statsEvent.failed ? 'failed' : 'successful');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.updateRunningState = () => {
|
||||||
|
this.state.running = (Boolean(this.state.started) && !this.state.finished) ||
|
||||||
|
(this.state.status === 'running') ||
|
||||||
|
(this.state.status === 'pending') ||
|
||||||
|
(this.state.status === 'waiting');
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateHostCounts = () => {
|
this.updateHostCounts = () => {
|
||||||
@@ -98,74 +132,66 @@ function JobStatusService (_moment_) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.hostCount = countedHostNames.length;
|
this.state.counts.hosts = countedHostNames.length;
|
||||||
this.hostStatusCounts = counts;
|
this.setHostStatusCounts(counts);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateStats = () => {
|
|
||||||
this.updateHostCounts();
|
|
||||||
|
|
||||||
if (this.statsEvent) {
|
|
||||||
this.setFinished(this.statsEvent.created);
|
|
||||||
this.setJobStatus(this.statsEvent.failed ? 'failed' : 'successful');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
this.isRunning = () => (Boolean(this.started) && !this.finished) ||
|
|
||||||
(this.jobStatus === 'running') ||
|
|
||||||
(this.jobStatus === 'pending') ||
|
|
||||||
(this.jobStatus === 'waiting');
|
|
||||||
|
|
||||||
this.isExpectingStatsEvent = () => (this.jobType === 'job') ||
|
|
||||||
(this.jobType === 'project_update');
|
|
||||||
|
|
||||||
this.getPlayCount = () => this.playCount;
|
|
||||||
this.getTaskCount = () => this.taskCount;
|
|
||||||
this.getHostCount = () => this.hostCount;
|
|
||||||
this.getHostStatusCounts = () => this.hostStatusCounts || {};
|
|
||||||
this.getJobStatus = () => this.jobStatus;
|
|
||||||
this.getProjectStatus = () => this.projectStatus;
|
|
||||||
this.getProjectUpdateId = () => this.projectUpdateId;
|
|
||||||
this.getElapsed = () => this.elapsed;
|
|
||||||
this.getStatsEvent = () => this.statsEvent;
|
|
||||||
this.getStarted = () => this.started;
|
|
||||||
this.getFinished = () => this.finished;
|
|
||||||
|
|
||||||
this.setJobStatus = status => {
|
this.setJobStatus = status => {
|
||||||
this.jobStatus = status;
|
this.state.status = status;
|
||||||
|
|
||||||
if (!this.isExpectingStatsEvent() && _.includes(FINISHED, status)) {
|
if (!this.isExpectingStatsEvent() && _.includes(FINISHED, status)) {
|
||||||
if (this.latestTime) {
|
if (this.latestTime) {
|
||||||
this.setFinished(this.latestTime);
|
this.setFinished(this.latestTime);
|
||||||
|
if (!this.state.started && this.state.elapsed) {
|
||||||
if (!this.started && this.elapsed) {
|
this.setStarted(moment(this.latestTime)
|
||||||
this.started = moment(this.latestTime).subtract(this.elapsed, 'seconds');
|
.subtract(this.state.elapsed, 'seconds'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.updateRunningState();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setElapsed = elapsed => {
|
||||||
|
this.state.elapsed = elapsed;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setStarted = started => {
|
||||||
|
this.state.started = started;
|
||||||
|
this.updateRunningState();
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setProjectStatus = status => {
|
this.setProjectStatus = status => {
|
||||||
this.projectStatus = status;
|
this.state.scm.status = status;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setProjectUpdateId = id => {
|
this.setProjectUpdateId = id => {
|
||||||
this.projectUpdateId = id;
|
this.state.scm.id = id;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setFinished = time => {
|
this.setFinished = time => {
|
||||||
this.finished = time;
|
this.state.finished = time;
|
||||||
|
this.updateRunningState();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setStatsEvent = data => {
|
||||||
|
this.statsEvent = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setHostStatusCounts = counts => {
|
||||||
|
this.state.hosts = counts;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.resetCounts = () => {
|
this.resetCounts = () => {
|
||||||
this.playCount = 0;
|
this.state.counts.plays = 0;
|
||||||
this.taskCount = 0;
|
this.state.counts.tasks = 0;
|
||||||
this.hostCount = 0;
|
this.state.counts.hosts = 0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
JobStatusService.$inject = [
|
JobStatusService.$inject = [
|
||||||
'moment',
|
'moment',
|
||||||
|
'JobMessageService',
|
||||||
];
|
];
|
||||||
|
|
||||||
export default JobStatusService;
|
export default JobStatusService;
|
||||||
|
|||||||
Reference in New Issue
Block a user