mirror of
https://github.com/ansible/awx.git
synced 2026-03-29 06:45:09 -02:30
Implement memory max (NodeList ejection) in real-time mode
This commit is contained in:
committed by
Jake McDermott
parent
d48f69317f
commit
5c3cf83d08
@@ -16,8 +16,8 @@ const record = {};
|
|||||||
|
|
||||||
let parent = null;
|
let parent = null;
|
||||||
let cache = [];
|
let cache = [];
|
||||||
|
let buffer = [];
|
||||||
|
|
||||||
const PAGE_LIMIT = 3;
|
|
||||||
const SCROLL_BUFFER = 250;
|
const SCROLL_BUFFER = 250;
|
||||||
const SCROLL_LOAD_DELAY = 50;
|
const SCROLL_LOAD_DELAY = 50;
|
||||||
const EVENT_START_TASK = 'playbook_on_task_start';
|
const EVENT_START_TASK = 'playbook_on_task_start';
|
||||||
@@ -67,13 +67,13 @@ function JobsIndexController (
|
|||||||
cache.push({ page: 1, lines: parsed.lines });
|
cache.push({ page: 1, lines: parsed.lines });
|
||||||
|
|
||||||
// Development helper(s)
|
// Development helper(s)
|
||||||
vm.clear = clear;
|
vm.clear = devClear;
|
||||||
|
|
||||||
// Stdout Navigation
|
// Stdout Navigation
|
||||||
vm.scroll = {
|
vm.scroll = {
|
||||||
lock: false,
|
isLocked: false,
|
||||||
display: false,
|
showBackToTop: false,
|
||||||
active: false,
|
isActive: false,
|
||||||
home: scrollHome,
|
home: scrollHome,
|
||||||
end: scrollEnd,
|
end: scrollEnd,
|
||||||
down: scrollPageDown,
|
down: scrollPageDown,
|
||||||
@@ -88,10 +88,13 @@ function JobsIndexController (
|
|||||||
// Real-time (active between JOB_START and JOB_END events only)
|
// Real-time (active between JOB_START and JOB_END events only)
|
||||||
$scope.$on(webSocketNamespace, processWebSocketEvents);
|
$scope.$on(webSocketNamespace, processWebSocketEvents);
|
||||||
vm.stream = {
|
vm.stream = {
|
||||||
active: false
|
isActive: false,
|
||||||
|
isRendering: false,
|
||||||
|
count: 0,
|
||||||
|
page: 1
|
||||||
};
|
};
|
||||||
|
|
||||||
$timeout(() => {
|
window.requestAnimationFrame(() => {
|
||||||
const table = $(ELEMENT_TBODY);
|
const table = $(ELEMENT_TBODY);
|
||||||
container = $(ELEMENT_CONTAINER);
|
container = $(ELEMENT_CONTAINER);
|
||||||
|
|
||||||
@@ -102,32 +105,72 @@ function JobsIndexController (
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear () {
|
|
||||||
const rows = $(ELEMENT_TBODY).children();
|
|
||||||
|
|
||||||
rows.empty();
|
|
||||||
rows.remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
function processWebSocketEvents (scope, data) {
|
function processWebSocketEvents (scope, data) {
|
||||||
vm.scroll.active = true;
|
vm.scroll.isActive = true;
|
||||||
|
|
||||||
if (data.event === JOB_START) {
|
if (data.event === JOB_START) {
|
||||||
vm.stream.active = true;
|
vm.stream.isActive = true;
|
||||||
vm.scroll.lock = true;
|
vm.scroll.isLocked = true;
|
||||||
} else if (data.event === JOB_END) {
|
} else if (data.event === JOB_END) {
|
||||||
vm.stream.active = false;
|
vm.stream.isActive = false;
|
||||||
vm.scroll.lock = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
append([data])
|
if (vm.stream.count % resource.page.size === 0) {
|
||||||
|
cache.push({
|
||||||
|
page: vm.stream.page
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.stream.page++;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.stream.count++;
|
||||||
|
buffer.push(data);
|
||||||
|
|
||||||
|
if (vm.stream.isRendering) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vm.stream.isRendering = true;
|
||||||
|
|
||||||
|
const events = buffer.slice(0, buffer.length);
|
||||||
|
|
||||||
|
buffer = [];
|
||||||
|
|
||||||
|
return render(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
function render (events) {
|
||||||
|
return shift()
|
||||||
|
.then(() => append(events))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (vm.scroll.lock) {
|
if (vm.scroll.isLocked) {
|
||||||
container[0].scrollTop = container[0].scrollHeight;
|
const height = container[0].scrollHeight;
|
||||||
|
container[0].scrollTop = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vm.stream.isActive) {
|
||||||
|
if (buffer.length) {
|
||||||
|
events = buffer.slice(0, buffer.length);
|
||||||
|
buffer = [];
|
||||||
|
|
||||||
|
return render(events)
|
||||||
|
.then(() => {
|
||||||
|
vm.stream.isRendering = false;
|
||||||
|
vm.scroll.isLocked = false;
|
||||||
|
vm.scroll.isActive = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vm.stream.isRendering = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function devClear () {
|
||||||
|
cache = [];
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
function next () {
|
function next () {
|
||||||
const config = {
|
const config = {
|
||||||
related: resource.related,
|
related: resource.related,
|
||||||
@@ -137,7 +180,7 @@ function next () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[2] getting next page', config.page, cache);
|
// console.log('[2] getting next page', config.page, cache);
|
||||||
return model.goToPage(config)
|
return model.goToPage(config)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data || !data.results) {
|
if (!data || !data.results) {
|
||||||
@@ -164,7 +207,7 @@ function prev () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[2] getting previous page', config.page, cache);
|
// console.log('[2] getting previous page', config.page, cache);
|
||||||
return model.goToPage(config)
|
return model.goToPage(config)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data || !data.results) {
|
if (!data || !data.results) {
|
||||||
@@ -188,88 +231,100 @@ function prev () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function append (events) {
|
function append (events) {
|
||||||
console.log('[4] appending next page');
|
// console.log('[4] appending next page');
|
||||||
|
|
||||||
return $q(resolve => {
|
return $q(resolve => {
|
||||||
const parsed = parseEvents(events);
|
window.requestAnimationFrame(() => {
|
||||||
const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parsed.html)));
|
const parsed = parseEvents(events);
|
||||||
const table = $(ELEMENT_TBODY);
|
const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parsed.html)));
|
||||||
const index = cache.length - 1;
|
const table = $(ELEMENT_TBODY);
|
||||||
|
const index = cache.length - 1;
|
||||||
|
|
||||||
cache[index].lines = parsed.lines;
|
if (cache[index].lines) {
|
||||||
|
cache[index].lines += parsed.lines;
|
||||||
|
} else {
|
||||||
|
cache[index].lines = parsed.lines;
|
||||||
|
}
|
||||||
|
|
||||||
table.append(rows);
|
table.append(rows);
|
||||||
$compile(rows.contents())($scope);
|
$compile(rows.contents())($scope);
|
||||||
$timeout(() => {
|
|
||||||
resolve();
|
return resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepend (events) {
|
function prepend (events) {
|
||||||
console.log('[4] prepending next page');
|
// console.log('[4] prepending next page');
|
||||||
|
|
||||||
return $q(resolve => {
|
return $q(resolve => {
|
||||||
const parsed = parseEvents(events);
|
window.requestAnimationFrame(() => {
|
||||||
const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parsed.html)));
|
const parsed = parseEvents(events);
|
||||||
const table = $(ELEMENT_TBODY);
|
const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parsed.html)));
|
||||||
|
const table = $(ELEMENT_TBODY);
|
||||||
|
|
||||||
cache[0].lines = parsed.lines;
|
cache[0].lines = parsed.lines;
|
||||||
|
|
||||||
table.prepend(rows);
|
table.prepend(rows);
|
||||||
$compile(rows.contents())($scope);
|
$compile(rows.contents())($scope);
|
||||||
|
|
||||||
$timeout(() => resolve(parsed.lines));
|
return resolve(parsed.lines);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function pop () {
|
function pop () {
|
||||||
console.log('[3] popping old page');
|
// console.log('[3] popping old page');
|
||||||
return $q(resolve => {
|
return $q(resolve => {
|
||||||
if (cache.length <= PAGE_LIMIT) {
|
if (cache.length <= resource.page.limit) {
|
||||||
console.log('[3.1] nothing to pop');
|
// console.log('[3.1] nothing to pop');
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ejected = cache.pop();
|
window.requestAnimationFrame(() => {
|
||||||
console.log('[3.1] popping', ejected);
|
const ejected = cache.pop();
|
||||||
const rows = $(ELEMENT_TBODY).children().slice(-ejected.lines);
|
// console.log('[3.1] popping', ejected);
|
||||||
|
const rows = $(ELEMENT_TBODY).children().slice(-ejected.lines);
|
||||||
|
|
||||||
rows.empty();
|
rows.empty();
|
||||||
rows.remove();
|
rows.remove();
|
||||||
|
|
||||||
$timeout(() => resolve(ejected));
|
return resolve(ejected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function shift () {
|
function shift () {
|
||||||
console.log('[3] shifting old page');
|
// console.log('[3] shifting old page');
|
||||||
return $q(resolve => {
|
return $q(resolve => {
|
||||||
if (cache.length <= PAGE_LIMIT) {
|
if (cache.length <= resource.page.limit) {
|
||||||
console.log('[3.1] nothing to shift');
|
// console.log('[3.1] nothing to shift');
|
||||||
return resolve();
|
return resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ejected = cache.shift();
|
window.requestAnimationFrame(() => {
|
||||||
console.log('[3.1] shifting', ejected);
|
const ejected = cache.shift();
|
||||||
const rows = $(ELEMENT_TBODY).children().slice(0, ejected.lines);
|
// console.log('[3.1] shifting', ejected);
|
||||||
|
const rows = $(ELEMENT_TBODY).children().slice(0, ejected.lines);
|
||||||
|
|
||||||
rows.empty();
|
rows.empty();
|
||||||
rows.remove();
|
rows.remove();
|
||||||
|
|
||||||
$timeout(() => resolve());
|
return resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function clear () {
|
function clear () {
|
||||||
console.log('[3] clearing pages');
|
// console.log('[3] clearing pages');
|
||||||
return $q(resolve => {
|
return $q(resolve => {
|
||||||
const rows = $(ELEMENT_TBODY).children();
|
window.requestAnimationFrame(() => {
|
||||||
|
const rows = $(ELEMENT_TBODY).children();
|
||||||
|
|
||||||
rows.empty();
|
rows.empty();
|
||||||
rows.remove();
|
rows.remove();
|
||||||
|
|
||||||
$timeout(() => resolve());
|
return resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -507,40 +562,40 @@ function toggle (uuid, menu) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onScroll () {
|
function onScroll () {
|
||||||
if (vm.scroll.active) {
|
if (vm.scroll.isActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vm.scroll.active = true;
|
vm.scroll.isActive = true;
|
||||||
|
|
||||||
$timeout(() => {
|
$timeout(() => {
|
||||||
const top = container[0].scrollTop;
|
const top = container[0].scrollTop;
|
||||||
const bottom = top + SCROLL_BUFFER + container[0].offsetHeight;
|
const bottom = top + SCROLL_BUFFER + container[0].offsetHeight;
|
||||||
|
|
||||||
if (top <= SCROLL_BUFFER) {
|
if (top <= SCROLL_BUFFER) {
|
||||||
console.log('[1] scroll to top');
|
// console.log('[1] scroll to top');
|
||||||
vm.scroll.display = false;
|
vm.scroll.showBackToTop = false;
|
||||||
|
|
||||||
prev()
|
prev()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('[5] scroll reset');
|
// console.log('[5] scroll reset');
|
||||||
vm.scroll.active = false;
|
vm.scroll.isActive = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
vm.scroll.display = true;
|
vm.scroll.showBackToTop = true;
|
||||||
|
|
||||||
if (bottom >= container[0].scrollHeight) {
|
if (bottom >= container[0].scrollHeight) {
|
||||||
console.log('[1] scroll to bottom');
|
// console.log('[1] scroll to bottom');
|
||||||
|
|
||||||
next()
|
next()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('[5] scroll reset');
|
// console.log('[5] scroll reset');
|
||||||
vm.scroll.active = false;
|
vm.scroll.isActive = false;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
vm.scroll.active = false;
|
vm.scroll.isActive = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, SCROLL_LOAD_DELAY);
|
}, SCROLL_LOAD_DELAY);
|
||||||
@@ -555,9 +610,9 @@ function scrollHome () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
vm.scroll.active = true;
|
vm.scroll.isActive = true;
|
||||||
|
|
||||||
console.log('[2] getting first page', config.page, cache);
|
// console.log('[2] getting first page', config.page, cache);
|
||||||
return model.goToPage(config)
|
return model.goToPage(config)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data || !data.results) {
|
if (!data || !data.results) {
|
||||||
@@ -571,14 +626,14 @@ function scrollHome () {
|
|||||||
return clear()
|
return clear()
|
||||||
.then(() => prepend(data.results))
|
.then(() => prepend(data.results))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
vm.scroll.active = false;
|
vm.scroll.isActive = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrollEnd () {
|
function scrollEnd () {
|
||||||
if (vm.scroll.lock) {
|
if (vm.scroll.isLocked) {
|
||||||
vm.scroll.lock = false;
|
vm.scroll.isLocked = false;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -591,9 +646,9 @@ function scrollEnd () {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
vm.scroll.active = true;
|
vm.scroll.isActive = true;
|
||||||
|
|
||||||
console.log('[2] getting last page', config.page, cache);
|
// console.log('[2] getting last page', config.page, cache);
|
||||||
return model.goToPage(config)
|
return model.goToPage(config)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (!data || !data.results) {
|
if (!data || !data.results) {
|
||||||
@@ -610,7 +665,7 @@ function scrollEnd () {
|
|||||||
const container = $(ELEMENT_CONTAINER)[0];
|
const container = $(ELEMENT_CONTAINER)[0];
|
||||||
|
|
||||||
container.scrollTop = container.scrollHeight;
|
container.scrollTop = container.scrollHeight;
|
||||||
vm.scroll.active = false;
|
vm.scroll.isActive = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<div class="pull-right" ng-click="vm.scroll.end()">
|
<div class="pull-right" ng-click="vm.scroll.end()">
|
||||||
<i class="at-Stdout-menuIcon--lg fa fa-angle-double-down"
|
<i class="at-Stdout-menuIcon--lg fa fa-angle-double-down"
|
||||||
ng-class=" { 'at-Stdout-menuIcon--active': vm.scroll.lock }"></i>
|
ng-class=" { 'at-Stdout-menuIcon--active': vm.scroll.isLocked }"></i>
|
||||||
</div>
|
</div>
|
||||||
<div class="pull-right" ng-click="vm.scroll.home()">
|
<div class="pull-right" ng-click="vm.scroll.home()">
|
||||||
<i class="at-Stdout-menuIcon--lg fa fa-angle-double-up"></i>
|
<i class="at-Stdout-menuIcon--lg fa fa-angle-double-up"></i>
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
<pre class="at-Stdout-container"><table><thead><tr><th class="at-Stdout-toggle"> </th><th class="at-Stdout-line"></th><th class="at-Stdout-event"></th></tr></thead><tbody id="atStdoutResultTable"></tbody></table></pre>
|
<pre class="at-Stdout-container"><table><thead><tr><th class="at-Stdout-toggle"> </th><th class="at-Stdout-line"></th><th class="at-Stdout-event"></th></tr></thead><tbody id="atStdoutResultTable"></tbody></table></pre>
|
||||||
|
|
||||||
<div ng-show="vm.scroll.display" class="at-Stdout-menuBottom">
|
<div ng-show="vm.scroll.showBackToTop" class="at-Stdout-menuBottom">
|
||||||
<div class="at-Stdout-menuIconGroup" ng-click="vm.scroll.home()">
|
<div class="at-Stdout-menuIconGroup" ng-click="vm.scroll.home()">
|
||||||
<p class="pull-left"><i class="fa fa-angle-double-up"></i></p>
|
<p class="pull-left"><i class="fa fa-angle-double-up"></i></p>
|
||||||
<p class="pull-right">Back to Top</p>
|
<p class="pull-right">Back to Top</p>
|
||||||
|
|||||||
@@ -430,7 +430,6 @@ function goToPage (config) {
|
|||||||
pageNumber = page;
|
pageNumber = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('pageNumber', page, pageNumber);
|
|
||||||
if (pageNumber < 1 || pageNumber > this.page.last) {
|
if (pageNumber < 1 || pageNumber > this.page.last) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user