mirror of
https://github.com/ansible/awx.git
synced 2026-03-11 06:29:31 -02:30
updates to job results performance
This commit is contained in:
@@ -2234,3 +2234,8 @@ a:hover {
|
|||||||
padding-left: 2px;
|
padding-left: 2px;
|
||||||
width: 14px;
|
width: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button[disabled],
|
||||||
|
html input[disabled] {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|||||||
@@ -35,11 +35,14 @@
|
|||||||
<div class="JobResultsStdOut-numberColumnPreload"></div>
|
<div class="JobResultsStdOut-numberColumnPreload"></div>
|
||||||
<div id='lineAnchor' class="JobResultsStdOut-lineAnchor"></div>
|
<div id='lineAnchor' class="JobResultsStdOut-lineAnchor"></div>
|
||||||
<div class="JobResultsStdOut-aLineOfStdOut"
|
<div class="JobResultsStdOut-aLineOfStdOut"
|
||||||
ng-show="tooManyEvents">
|
ng-show="tooManyEvents || tooManyPastEvents">
|
||||||
<div class="JobResultsStdOut-lineNumberColumn">
|
<div class="JobResultsStdOut-lineNumberColumn">
|
||||||
<span class="JobResultsStdOut-lineExpander"> </span>
|
<span class="JobResultsStdOut-lineExpander"> </span>
|
||||||
</div>
|
</div>
|
||||||
<div class="JobResultsStdOut-stdoutColumn JobResultsStdOut-stdoutColumn--tooMany">The standard output is too large to display. Please specify additional filters to narrow the standard out.</div>
|
<div class="JobResultsStdOut-stdoutColumn JobResultsStdOut-stdoutColumn--tooMany"
|
||||||
|
ng-show="tooManyEvents">The standard output is too large to display. Please specify additional filters to narrow the standard out.</div>
|
||||||
|
<div class="JobResultsStdOut-stdoutColumn JobResultsStdOut-stdoutColumn--tooMany"
|
||||||
|
ng-show="tooManyPastEvents">Too much previous output to display. Showing running standard output.</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="followAnchor"
|
<div id="followAnchor"
|
||||||
class="JobResultsStdOut-followAnchor">
|
class="JobResultsStdOut-followAnchor">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
export default ['jobData', 'jobDataOptions', 'jobLabels', 'jobFinished', 'count', '$scope', 'ParseTypeChange', 'ParseVariableString', 'jobResultsService', 'eventQueue', '$compile', '$log', 'Dataset', '$q', 'Rest', '$state', 'QuerySet', '$rootScope', 'moment', 'i18n',
|
export default ['jobData', 'jobDataOptions', 'jobLabels', 'jobFinished', 'count', '$scope', 'ParseTypeChange', 'ParseVariableString', 'jobResultsService', 'eventQueue', '$compile', '$log', 'Dataset', '$q', 'Rest', '$state', 'QuerySet', '$rootScope', 'moment', '$stateParams', 'i18n',
|
||||||
function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTypeChange, ParseVariableString, jobResultsService, eventQueue, $compile, $log, Dataset, $q, Rest, $state, QuerySet, $rootScope, moment, i18n) {
|
function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTypeChange, ParseVariableString, jobResultsService, eventQueue, $compile, $log, Dataset, $q, Rest, $state, QuerySet, $rootScope, moment, $stateParams, i18n) {
|
||||||
var toDestroy = [];
|
var toDestroy = [];
|
||||||
var cancelRequests = false;
|
var cancelRequests = false;
|
||||||
|
|
||||||
@@ -9,6 +9,25 @@ function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTy
|
|||||||
// this allows you to manage the timing of rest-call based events as
|
// this allows you to manage the timing of rest-call based events as
|
||||||
// filters are updated. see processPage for more info
|
// filters are updated. see processPage for more info
|
||||||
var currentContext = 1;
|
var currentContext = 1;
|
||||||
|
$scope.firstCounterFromSocket = -1;
|
||||||
|
|
||||||
|
// if the user enters the page mid-run, reset the search to include a param
|
||||||
|
// to only grab events less than the first counter from the websocket events
|
||||||
|
toDestroy.push($scope.$watch('firstCounterFromSocket', function(counter) {
|
||||||
|
if (counter > -1) {
|
||||||
|
// make it so that the search include a counter less than the
|
||||||
|
// first counter from the socket
|
||||||
|
let params = _.cloneDeep($stateParams.job_event_search);
|
||||||
|
params.counter__lte = "" + counter;
|
||||||
|
|
||||||
|
Dataset = QuerySet.search(jobData.related.job_events,
|
||||||
|
params);
|
||||||
|
|
||||||
|
Dataset.then(function(actualDataset) {
|
||||||
|
$scope.job_event_dataset = actualDataset.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
// used for tag search
|
// used for tag search
|
||||||
$scope.job_event_dataset = Dataset.data;
|
$scope.job_event_dataset = Dataset.data;
|
||||||
@@ -424,57 +443,87 @@ function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTy
|
|||||||
|
|
||||||
// grab non-header recap lines
|
// grab non-header recap lines
|
||||||
toDestroy.push($scope.$watch('job_event_dataset', function(val) {
|
toDestroy.push($scope.$watch('job_event_dataset', function(val) {
|
||||||
eventQueue.initialize();
|
if (val) {
|
||||||
|
eventQueue.initialize();
|
||||||
|
|
||||||
Object.keys($scope.events)
|
Object.keys($scope.events)
|
||||||
.forEach(v => {
|
.forEach(v => {
|
||||||
// dont destroy scope events for skeleton lines
|
// dont destroy scope events for skeleton lines
|
||||||
let name = $scope.events[v].event.name;
|
let name = $scope.events[v].event.name;
|
||||||
|
|
||||||
if (!(name === "playbook_on_play_start" ||
|
if (!(name === "playbook_on_play_start" ||
|
||||||
name === "playbook_on_task_start" ||
|
name === "playbook_on_task_start" ||
|
||||||
name === "playbook_on_stats")) {
|
name === "playbook_on_stats")) {
|
||||||
$scope.events[v].$destroy();
|
$scope.events[v].$destroy();
|
||||||
$scope.events[v] = null;
|
$scope.events[v] = null;
|
||||||
delete $scope.events[v];
|
delete $scope.events[v];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// pause websocket events from coming in to the pane
|
||||||
|
$scope.gotPreviouslyRanEvents = $q.defer();
|
||||||
|
currentContext += 1;
|
||||||
|
|
||||||
|
let context = currentContext;
|
||||||
|
|
||||||
|
$( ".JobResultsStdOut-aLineOfStdOut.not_skeleton" ).remove();
|
||||||
|
$scope.hasSkeleton.promise.then(() => {
|
||||||
|
if (val.count > parseInt(val.maxEvents)) {
|
||||||
|
$(".header_task").hide();
|
||||||
|
$(".header_play").hide();
|
||||||
|
$scope.standardOutTooltip = '<div class="JobResults-downloadTooLarge"><div>' +
|
||||||
|
i18n._('The output is too large to display. Please download.') +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="JobResults-downloadTooLarge--icon">' +
|
||||||
|
'<span class="fa-stack fa-lg">' +
|
||||||
|
'<i class="fa fa-circle fa-stack-1x"></i>' +
|
||||||
|
'<i class="fa fa-stack-1x icon-job-stdout-download-tooltip"></i>' +
|
||||||
|
'</span>' +
|
||||||
|
'</div>' +
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
if ($scope.job_status === "successful" ||
|
||||||
|
$scope.job_status === "failed" ||
|
||||||
|
$scope.job_status === "error" ||
|
||||||
|
$scope.job_status === "canceled") {
|
||||||
|
$scope.tooManyEvents = true;
|
||||||
|
$scope.tooManyPastEvents = false;
|
||||||
|
} else {
|
||||||
|
$scope.tooManyPastEvents = true;
|
||||||
|
$scope.tooManyEvents = false;
|
||||||
|
$scope.gotPreviouslyRanEvents.resolve("");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$(".header_task").show();
|
||||||
|
$(".header_play").show();
|
||||||
|
$scope.tooManyEvents = false;
|
||||||
|
$scope.tooManyPastEvents = false;
|
||||||
|
processPage(val, context);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
// pause websocket events from coming in to the pane
|
|
||||||
$scope.gotPreviouslyRanEvents = $q.defer();
|
|
||||||
currentContext += 1;
|
|
||||||
|
|
||||||
let context = currentContext;
|
|
||||||
|
|
||||||
$( ".JobResultsStdOut-aLineOfStdOut.not_skeleton" ).remove();
|
|
||||||
$scope.hasSkeleton.promise.then(() => {
|
|
||||||
if (val.count > parseInt(val.maxEvents)) {
|
|
||||||
$(".header_task").hide();
|
|
||||||
$(".header_play").hide();
|
|
||||||
$scope.tooManyEvents = true;
|
|
||||||
$scope.standardOutTooltip = '<div class="JobResults-downloadTooLarge"><div>' +
|
|
||||||
i18n._('The output is too large to display. Please download.') +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="JobResults-downloadTooLarge--icon">' +
|
|
||||||
'<span class="fa-stack fa-lg">' +
|
|
||||||
'<i class="fa fa-circle fa-stack-1x"></i>' +
|
|
||||||
'<i class="fa fa-stack-1x icon-job-stdout-download-tooltip"></i>' +
|
|
||||||
'</span>' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>';
|
|
||||||
} else {
|
|
||||||
$(".header_task").show();
|
|
||||||
$(".header_play").show();
|
|
||||||
$scope.tooManyEvents = false;
|
|
||||||
processPage(val, context);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Processing of job_events messages from the websocket
|
// Processing of job_events messages from the websocket
|
||||||
toDestroy.push($scope.$on(`ws-job_events-${$scope.job.id}`, function(e, data) {
|
toDestroy.push($scope.$on(`ws-job_events-${$scope.job.id}`, function(e, data) {
|
||||||
|
|
||||||
|
// use the lowest counter coming over the socket to retrigger pull data
|
||||||
|
// to only be for stuff lower than that id
|
||||||
|
//
|
||||||
|
// only do this for entering the jobs page mid-run (thus the
|
||||||
|
// data.counter is 1 conditional
|
||||||
|
if (data.counter === 1) {
|
||||||
|
$scope.firstCounterFromSocket = -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($scope.firstCounterFromSocket !== -2 &&
|
||||||
|
$scope.firstCounterFromSocket === -1 ||
|
||||||
|
data.counter < $scope.firstCounterFromSocket) {
|
||||||
|
$scope.firstCounterFromSocket = data.counter;
|
||||||
|
}
|
||||||
|
|
||||||
$q.all([$scope.gotPreviouslyRanEvents.promise,
|
$q.all([$scope.gotPreviouslyRanEvents.promise,
|
||||||
$scope.hasSkeleton.promise]).then(() => {
|
$scope.hasSkeleton.promise]).then(() => {
|
||||||
// put the line in the
|
// put the line in the
|
||||||
|
|||||||
@@ -506,7 +506,9 @@
|
|||||||
list="list"
|
list="list"
|
||||||
collection="job_events"
|
collection="job_events"
|
||||||
dataset="job_event_dataset"
|
dataset="job_event_dataset"
|
||||||
search-tags="searchTags">
|
search-tags="searchTags"
|
||||||
|
disable-search="job_status == 'running' ||
|
||||||
|
job_status=='pending'">
|
||||||
</smart-search>
|
</smart-search>
|
||||||
<job-results-standard-out></job-results-standard-out>
|
<job-results-standard-out></job-results-standard-out>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,6 +6,12 @@
|
|||||||
|
|
||||||
import {templateUrl} from '../shared/template-url/template-url.factory';
|
import {templateUrl} from '../shared/template-url/template-url.factory';
|
||||||
|
|
||||||
|
const defaultParams = {
|
||||||
|
page_size: "200",
|
||||||
|
order_by: 'start_line',
|
||||||
|
not__event__in: 'playbook_on_start,playbook_on_play_start,playbook_on_task_start,playbook_on_stats'
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'jobDetail',
|
name: 'jobDetail',
|
||||||
url: '/jobs/{id: int}',
|
url: '/jobs/{id: int}',
|
||||||
@@ -24,11 +30,7 @@ export default {
|
|||||||
},
|
},
|
||||||
params: {
|
params: {
|
||||||
job_event_search: {
|
job_event_search: {
|
||||||
value: {
|
value: defaultParams,
|
||||||
page_size: 100,
|
|
||||||
order_by: 'id',
|
|
||||||
not__event__in: 'playbook_on_start,playbook_on_play_start,playbook_on_task_start,playbook_on_stats'
|
|
||||||
},
|
|
||||||
dynamic: true,
|
dynamic: true,
|
||||||
squash: ''
|
squash: ''
|
||||||
}
|
}
|
||||||
@@ -56,7 +58,7 @@ export default {
|
|||||||
// flashing as rest data comes in. If the job is finished and
|
// 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
|
// there's a playbook_on_stats event, go ahead and resolve the count
|
||||||
// so you don't get that flashing!
|
// so you don't get that flashing!
|
||||||
count: ['jobData', 'jobResultsService', 'Rest', '$q', function(jobData, jobResultsService, Rest, $q) {
|
count: ['jobData', 'jobResultsService', 'Rest', '$q', '$stateParams', '$state', function(jobData, jobResultsService, Rest, $q, $stateParams, $state) {
|
||||||
var defer = $q.defer();
|
var defer = $q.defer();
|
||||||
if (jobData.finished) {
|
if (jobData.finished) {
|
||||||
// if the job is finished, grab the playbook_on_stats
|
// if the job is finished, grab the playbook_on_stats
|
||||||
@@ -92,6 +94,15 @@ export default {
|
|||||||
}, countFinished: false});
|
}, countFinished: false});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
// make sure to not include any extra
|
||||||
|
// search params for a running job (because we can't filter
|
||||||
|
// incoming job events)
|
||||||
|
if (!_.isEqual($stateParams.job_event_search, defaultParams)) {
|
||||||
|
let params = _.cloneDeep($stateParams);
|
||||||
|
params.job_event_search = defaultParams;
|
||||||
|
$state.go('.', params, { reload: true });
|
||||||
|
}
|
||||||
|
|
||||||
// job isn't finished so just send an empty count and read
|
// job isn't finished so just send an empty count and read
|
||||||
// from events
|
// from events
|
||||||
defer.resolve({val: {
|
defer.resolve({val: {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export default ['templateUrl',
|
|||||||
dataset: '=',
|
dataset: '=',
|
||||||
collection: '=',
|
collection: '=',
|
||||||
searchTags: '=',
|
searchTags: '=',
|
||||||
|
disableSearch: '='
|
||||||
},
|
},
|
||||||
controller: 'SmartSearchController',
|
controller: 'SmartSearchController',
|
||||||
templateUrl: templateUrl('shared/smart-search/smart-search')
|
templateUrl: templateUrl('shared/smart-search/smart-search')
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
<div class="SmartSearch-searchTermContainer">
|
<div class="SmartSearch-searchTermContainer">
|
||||||
<!-- string search input -->
|
<!-- string search input -->
|
||||||
<form name="smartSearch" class="SmartSearch-form" aw-enter-key="add(searchTerm)" novalidate>
|
<form name="smartSearch" class="SmartSearch-form" aw-enter-key="add(searchTerm)" novalidate>
|
||||||
<input class="SmartSearch-input" ng-model="searchTerm" placeholder="Search">
|
<input class="SmartSearch-input" ng-model="searchTerm" placeholder="{{disableSearch ? 'Cannot search running job' : 'Search'}}"
|
||||||
|
ng-disabled="disableSearch">
|
||||||
</form>
|
</form>
|
||||||
<div type="submit" class="SmartSearch-searchButton" ng-disabled="!searchTerm" ng-click="add(searchTerm)">
|
<div type="submit" class="SmartSearch-searchButton" ng-disabled="!searchTerm" ng-click="add(searchTerm)">
|
||||||
<i class="fa fa-search"></i>
|
<i class="fa fa-search"></i>
|
||||||
|
|||||||
Reference in New Issue
Block a user