mirror of
https://github.com/ansible/awx.git
synced 2024-11-01 16:51:11 +03:00
maintain correct page counts on running jobs
This commit is contained in:
parent
503668141b
commit
11e7dcd0dc
132
awx/ui/client/features/output/api.events.service.js
Normal file
132
awx/ui/client/features/output/api.events.service.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
const PAGE_LIMIT = 5;
|
||||||
|
const PAGE_SIZE = 50;
|
||||||
|
|
||||||
|
const BASE_PARAMS = {
|
||||||
|
order_by: 'start_line',
|
||||||
|
page_size: PAGE_SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
const merge = (...objs) => _.merge({}, ...objs);
|
||||||
|
|
||||||
|
const getInitialState = params => ({
|
||||||
|
results: [],
|
||||||
|
count: 0,
|
||||||
|
previous: 1,
|
||||||
|
page: 1,
|
||||||
|
next: 1,
|
||||||
|
last: 1,
|
||||||
|
params: merge(BASE_PARAMS, params),
|
||||||
|
});
|
||||||
|
|
||||||
|
function JobEventsApiService ($http, $q) {
|
||||||
|
this.init = (endpoint, params) => {
|
||||||
|
this.keys = [];
|
||||||
|
this.cache = {};
|
||||||
|
this.pageSizes = {};
|
||||||
|
this.endpoint = endpoint;
|
||||||
|
this.state = getInitialState(params);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getLastPage = count => Math.ceil(count / this.state.params.page_size);
|
||||||
|
|
||||||
|
this.fetch = () => {
|
||||||
|
delete this.cache;
|
||||||
|
delete this.keys;
|
||||||
|
delete this.pageSizes;
|
||||||
|
|
||||||
|
this.cache = {};
|
||||||
|
this.keys = [];
|
||||||
|
this.pageSizes = {};
|
||||||
|
|
||||||
|
return this.getPage(1).then(() => this);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getPage = number => {
|
||||||
|
if (number < 1 || number > this.state.last) {
|
||||||
|
return $q.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.cache[number]) {
|
||||||
|
if (this.pageSizes[number] === PAGE_SIZE) {
|
||||||
|
return this.cache[number];
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this.pageSizes[number];
|
||||||
|
delete this.cache[number];
|
||||||
|
|
||||||
|
this.keys.splice(this.keys.indexOf(number));
|
||||||
|
}
|
||||||
|
|
||||||
|
const { params } = this.state;
|
||||||
|
|
||||||
|
delete params.page;
|
||||||
|
|
||||||
|
params.page = number;
|
||||||
|
|
||||||
|
const promise = $http.get(this.endpoint, { params })
|
||||||
|
.then(({ data }) => {
|
||||||
|
const { results, count } = data;
|
||||||
|
|
||||||
|
this.state.results = results;
|
||||||
|
this.state.count = count;
|
||||||
|
this.state.page = number;
|
||||||
|
this.state.last = this.getLastPage(count);
|
||||||
|
this.state.previous = Math.max(1, number - 1);
|
||||||
|
this.state.next = Math.min(this.state.last, number + 1);
|
||||||
|
|
||||||
|
this.pageSizes[number] = results.length;
|
||||||
|
|
||||||
|
return { results, page: number };
|
||||||
|
});
|
||||||
|
|
||||||
|
this.cache[number] = promise;
|
||||||
|
this.keys.push(number);
|
||||||
|
|
||||||
|
if (this.keys.length > PAGE_LIMIT) {
|
||||||
|
delete this.cache[this.keys.shift()];
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.first = () => this.getPage(1);
|
||||||
|
this.next = () => this.getPage(this.state.next);
|
||||||
|
this.previous = () => this.getPage(this.state.previous);
|
||||||
|
|
||||||
|
this.last = () => {
|
||||||
|
const params = merge({}, this.state.params);
|
||||||
|
|
||||||
|
delete params.page;
|
||||||
|
delete params.order_by;
|
||||||
|
|
||||||
|
params.page = 1;
|
||||||
|
params.order_by = '-start_line';
|
||||||
|
|
||||||
|
const promise = $http.get(this.endpoint, { params })
|
||||||
|
.then(({ data }) => {
|
||||||
|
const { results, count } = data;
|
||||||
|
const lastPage = this.getLastPage(count);
|
||||||
|
|
||||||
|
results.reverse();
|
||||||
|
const shifted = results.splice(count % PAGE_SIZE);
|
||||||
|
|
||||||
|
this.state.results = shifted;
|
||||||
|
this.state.count = count;
|
||||||
|
this.state.page = lastPage;
|
||||||
|
this.state.next = lastPage;
|
||||||
|
this.state.last = lastPage;
|
||||||
|
this.state.previous = Math.max(1, this.state.page - 1);
|
||||||
|
|
||||||
|
return { results: shifted, page: lastPage };
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
JobEventsApiService.$inject = [
|
||||||
|
'$http',
|
||||||
|
'$q'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default JobEventsApiService;
|
@ -7,7 +7,6 @@ let resource;
|
|||||||
let scroll;
|
let scroll;
|
||||||
let engine;
|
let engine;
|
||||||
let status;
|
let status;
|
||||||
let $http;
|
|
||||||
|
|
||||||
let vm;
|
let vm;
|
||||||
let streaming;
|
let streaming;
|
||||||
@ -23,7 +22,6 @@ function JobsIndexController (
|
|||||||
_$compile_,
|
_$compile_,
|
||||||
_$q_,
|
_$q_,
|
||||||
_status_,
|
_status_,
|
||||||
_$http_,
|
|
||||||
) {
|
) {
|
||||||
vm = this || {};
|
vm = this || {};
|
||||||
|
|
||||||
@ -37,7 +35,6 @@ function JobsIndexController (
|
|||||||
render = _render_;
|
render = _render_;
|
||||||
engine = _engine_;
|
engine = _engine_;
|
||||||
status = _status_;
|
status = _status_;
|
||||||
$http = _$http_;
|
|
||||||
|
|
||||||
// Development helper(s)
|
// Development helper(s)
|
||||||
vm.clear = devClear;
|
vm.clear = devClear;
|
||||||
@ -128,37 +125,20 @@ function handleJobEvent (data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function attachToRunningJob () {
|
function attachToRunningJob () {
|
||||||
const target = `${resource.model.get('url')}${resource.related}/`;
|
if (!status.state.running) {
|
||||||
const params = { order_by: '-created', page_size: resource.page.size };
|
return $q.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
scroll.pause();
|
return page.last()
|
||||||
|
.then(events => {
|
||||||
return render.clear()
|
if (!events) {
|
||||||
.then(() => $http.get(target, { params }))
|
|
||||||
.then(res => {
|
|
||||||
const { results } = res.data;
|
|
||||||
|
|
||||||
const minLine = 1 + Math.max(...results.map(event => event.end_line));
|
|
||||||
const maxCount = Math.max(...results.map(event => event.counter));
|
|
||||||
|
|
||||||
const lastPage = resource.model.updateCount(maxCount);
|
|
||||||
|
|
||||||
page.emptyCache(lastPage);
|
|
||||||
page.addPage(lastPage, [], true);
|
|
||||||
|
|
||||||
engine.setMinLine(minLine);
|
|
||||||
|
|
||||||
if (resource.model.page.current === lastPage) {
|
|
||||||
return $q.resolve();
|
return $q.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
return append(results);
|
const minLine = 1 + Math.max(...events.map(event => event.end_line));
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
scroll.setScrollPosition(scroll.getScrollHeight());
|
|
||||||
scroll.resume();
|
|
||||||
|
|
||||||
return $q.resolve();
|
return render.clear()
|
||||||
|
.then(() => engine.setMinLine(minLine));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,11 +273,11 @@ function scrollEnd () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return render.clear()
|
return render.clear()
|
||||||
.then(() => append(events))
|
.then(() => append(events));
|
||||||
.then(() => {
|
})
|
||||||
scroll.setScrollPosition(scroll.getScrollHeight());
|
.then(() => {
|
||||||
scroll.resume();
|
scroll.setScrollPosition(scroll.getScrollHeight());
|
||||||
});
|
scroll.resume();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +359,6 @@ JobsIndexController.$inject = [
|
|||||||
'$compile',
|
'$compile',
|
||||||
'$q',
|
'$q',
|
||||||
'JobStatusService',
|
'JobStatusService',
|
||||||
'$http',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
module.exports = JobsIndexController;
|
module.exports = JobsIndexController;
|
||||||
|
@ -9,6 +9,7 @@ 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 MessageService from '~features/output/message.service';
|
||||||
|
import EventsApiService from '~features/output/api.events.service';
|
||||||
import LegacyRedirect from '~features/output/legacy.route';
|
import LegacyRedirect from '~features/output/legacy.route';
|
||||||
|
|
||||||
import DetailsComponent from '~features/output/details.component';
|
import DetailsComponent from '~features/output/details.component';
|
||||||
@ -35,7 +36,8 @@ function resolveResource (
|
|||||||
InventoryUpdate,
|
InventoryUpdate,
|
||||||
$stateParams,
|
$stateParams,
|
||||||
qs,
|
qs,
|
||||||
Wait
|
Wait,
|
||||||
|
eventsApi,
|
||||||
) {
|
) {
|
||||||
const { id, type, handleErrors } = $stateParams;
|
const { id, type, handleErrors } = $stateParams;
|
||||||
const { job_event_search } = $stateParams; // eslint-disable-line camelcase
|
const { job_event_search } = $stateParams; // eslint-disable-line camelcase
|
||||||
@ -86,23 +88,29 @@ function resolveResource (
|
|||||||
Object.assign(config.params, query);
|
Object.assign(config.params, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let model;
|
||||||
|
|
||||||
Wait('start');
|
Wait('start');
|
||||||
const resourcePromise = new Resource(['get', 'options'], [id, id])
|
const resourcePromise = new Resource(['get', 'options'], [id, id])
|
||||||
.then(model => {
|
.then(job => {
|
||||||
const promises = [model.getStats()];
|
const endpoint = `${job.get('url')}${related}/`;
|
||||||
|
eventsApi.init(endpoint, config.params);
|
||||||
|
|
||||||
if (model.has('related.labels')) {
|
const promises = [job.getStats(), eventsApi.fetch()];
|
||||||
promises.push(model.extend('get', 'labels'));
|
|
||||||
|
if (job.has('related.labels')) {
|
||||||
|
promises.push(job.extend('get', 'labels'));
|
||||||
}
|
}
|
||||||
|
|
||||||
promises.push(model.extend('get', related, config));
|
model = job;
|
||||||
return Promise.all(promises);
|
return Promise.all(promises);
|
||||||
})
|
})
|
||||||
.then(([stats, model]) => ({
|
.then(([stats, events]) => ({
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
stats,
|
stats,
|
||||||
model,
|
model,
|
||||||
|
events,
|
||||||
related,
|
related,
|
||||||
ws: {
|
ws: {
|
||||||
events: `${WS_PREFIX}-${key}-${id}`,
|
events: `${WS_PREFIX}-${key}-${id}`,
|
||||||
@ -217,6 +225,7 @@ function JobsRun ($stateRegistry, strings) {
|
|||||||
'$stateParams',
|
'$stateParams',
|
||||||
'QuerySet',
|
'QuerySet',
|
||||||
'Wait',
|
'Wait',
|
||||||
|
'JobEventsApiService',
|
||||||
resolveResource
|
resolveResource
|
||||||
],
|
],
|
||||||
breadcrumbLabel: [
|
breadcrumbLabel: [
|
||||||
@ -246,6 +255,7 @@ angular
|
|||||||
.service('JobEventEngine', EngineService)
|
.service('JobEventEngine', EngineService)
|
||||||
.service('JobStatusService', StatusService)
|
.service('JobStatusService', StatusService)
|
||||||
.service('JobMessageService', MessageService)
|
.service('JobMessageService', MessageService)
|
||||||
|
.service('JobEventsApiService', EventsApiService)
|
||||||
.component('atJobSearch', SearchComponent)
|
.component('atJobSearch', SearchComponent)
|
||||||
.component('atJobStats', StatsComponent)
|
.component('atJobStats', StatsComponent)
|
||||||
.component('atJobDetails', DetailsComponent)
|
.component('atJobDetails', DetailsComponent)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
function JobPageService ($q) {
|
function JobPageService ($q) {
|
||||||
this.init = ({ resource }) => {
|
this.init = ({ resource }) => {
|
||||||
this.resource = resource;
|
this.resource = resource;
|
||||||
|
this.api = this.resource.events;
|
||||||
|
|
||||||
this.page = {
|
this.page = {
|
||||||
limit: this.resource.page.pageLimit,
|
limit: this.resource.page.pageLimit,
|
||||||
@ -125,8 +126,9 @@ function JobPageService ($q) {
|
|||||||
number = number || reference.state.current;
|
number = number || reference.state.current;
|
||||||
|
|
||||||
reference.state.first = number;
|
reference.state.first = number;
|
||||||
reference.state.last = number;
|
|
||||||
reference.state.current = number;
|
reference.state.current = number;
|
||||||
|
reference.state.last = number;
|
||||||
|
|
||||||
reference.cache.splice(0, reference.cache.length);
|
reference.cache.splice(0, reference.cache.length);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -203,9 +205,9 @@ function JobPageService ($q) {
|
|||||||
|
|
||||||
this.next = () => {
|
this.next = () => {
|
||||||
const reference = this.getActiveReference();
|
const reference = this.getActiveReference();
|
||||||
const config = this.buildRequestConfig(reference.state.last + 1);
|
const number = reference.state.last + 1;
|
||||||
|
|
||||||
return this.resource.model.goToPage(config)
|
return this.api.getPage(number)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data || !data.results) {
|
if (!data || !data.results) {
|
||||||
return $q.resolve();
|
return $q.resolve();
|
||||||
@ -219,9 +221,8 @@ function JobPageService ($q) {
|
|||||||
|
|
||||||
this.previous = () => {
|
this.previous = () => {
|
||||||
const reference = this.getActiveReference();
|
const reference = this.getActiveReference();
|
||||||
const config = this.buildRequestConfig(reference.state.first - 1);
|
|
||||||
|
|
||||||
return this.resource.model.goToPage(config)
|
return this.api.getPage(reference.state.first - 1)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data || !data.results) {
|
if (!data || !data.results) {
|
||||||
return $q.resolve();
|
return $q.resolve();
|
||||||
@ -233,45 +234,29 @@ function JobPageService ($q) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.last = () => {
|
this.last = () => this.api.last()
|
||||||
const config = this.buildRequestConfig('last');
|
.then(data => {
|
||||||
|
if (!data || !data.results || !data.results.length > 0) {
|
||||||
|
return $q.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
return this.resource.model.goToPage(config)
|
this.emptyCache(data.page);
|
||||||
.then(data => {
|
this.addPage(data.page, [], true);
|
||||||
if (!data || !data.results) {
|
|
||||||
return $q.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emptyCache(data.page);
|
return data.results;
|
||||||
this.addPage(data.page, [], true);
|
});
|
||||||
|
|
||||||
return data.results;
|
this.first = () => this.api.first()
|
||||||
});
|
.then(data => {
|
||||||
};
|
if (!data || !data.results) {
|
||||||
|
return $q.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
this.first = () => {
|
this.emptyCache(data.page);
|
||||||
const config = this.buildRequestConfig('first');
|
this.addPage(data.page, [], false);
|
||||||
|
|
||||||
return this.resource.model.goToPage(config)
|
return data.results;
|
||||||
.then(data => {
|
});
|
||||||
if (!data || !data.results) {
|
|
||||||
return $q.resolve();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.emptyCache(data.page);
|
|
||||||
this.addPage(data.page, [], false);
|
|
||||||
|
|
||||||
return data.results;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
this.buildRequestConfig = number => ({
|
|
||||||
page: number,
|
|
||||||
related: this.resource.related,
|
|
||||||
params: {
|
|
||||||
order_by: 'start_line'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.getActiveReference = () => (this.isBookmarkSet() ?
|
this.getActiveReference = () => (this.isBookmarkSet() ?
|
||||||
this.getReference(true) : this.getReference());
|
this.getReference(true) : this.getReference());
|
||||||
|
Loading…
Reference in New Issue
Block a user