render missing lines instead of auto-unfollowing

This commit is contained in:
Jake McDermott
2018-08-20 23:20:40 -04:00
parent 138f8a45ae
commit 0bc9b1d431
3 changed files with 154 additions and 88 deletions

View File

@@ -31,12 +31,6 @@ function onFrames (events) {
} }
const popCount = events.length - render.getCapacity(); const popCount = events.length - render.getCapacity();
const isAttached = events.length > 0;
if (!isAttached) {
stopFollowing();
return $q.resolve();
}
if (!vm.isFollowing && canStartFollowing()) { if (!vm.isFollowing && canStartFollowing()) {
startFollowing(); startFollowing();
@@ -58,7 +52,7 @@ function onFrames (events) {
scroll.scrollToBottom(); scroll.scrollToBottom();
} }
return render.pushFrames(events); return render.pushFront(events);
}) })
.then(() => { .then(() => {
if (vm.isFollowing) { if (vm.isFollowing) {
@@ -80,11 +74,18 @@ function firstRange () {
return $q.resolve(); return $q.resolve();
} }
stopFollowing();
lockFollow = true;
if (slide.isOnFirstPage()) {
scroll.resetScrollPosition();
return $q.resolve();
}
scroll.pause(); scroll.pause();
lockFrames = true; lockFrames = true;
stopFollowing();
return render.clear() return render.clear()
.then(() => slide.getFirst()) .then(() => slide.getFirst())
.then(results => render.pushFront(results)) .then(results => render.pushFront(results))
@@ -97,7 +98,7 @@ function firstRange () {
}) })
.finally(() => { .finally(() => {
scroll.resume(); scroll.resume();
lockFrames = false; lockFollow = false;
}); });
} }
@@ -112,10 +113,6 @@ function nextRange () {
return $q.resolve(); return $q.resolve();
} }
if (slide.getTailCounter() >= slide.getMaxCounter()) {
return $q.resolve();
}
scroll.pause(); scroll.pause();
lockFrames = true; lockFrames = true;
@@ -129,6 +126,8 @@ function nextRange () {
.finally(() => { .finally(() => {
scroll.resume(); scroll.resume();
lockFrames = false; lockFrames = false;
return $q.resolve();
}); });
} }
@@ -138,8 +137,8 @@ function previousRange () {
} }
scroll.pause(); scroll.pause();
lockFrames = true;
stopFollowing(); stopFollowing();
lockFrames = true;
let initialPosition; let initialPosition;
let popHeight; let popHeight;
@@ -182,13 +181,15 @@ function lastRange () {
.then(() => slide.getLast()) .then(() => slide.getLast())
.then(results => render.pushFront(results)) .then(results => render.pushFront(results))
.then(() => { .then(() => {
stream.setMissingCounterThreshold(slide.getTailCounter() + 1);
scroll.scrollToBottom(); scroll.scrollToBottom();
lockFrames = false;
return $q.resolve(); return $q.resolve();
}) })
.finally(() => { .finally(() => {
scroll.resume(); scroll.resume();
lockFrames = false;
return $q.resolve(); return $q.resolve();
}); });
@@ -204,13 +205,12 @@ function menuLastRange () {
lockFollow = false; lockFollow = false;
if (slide.isOnLastPage()) { return lastRange()
scroll.scrollToBottom(); .then(() => {
startFollowing();
return $q.resolve(); return $q.resolve();
} });
return last();
} }
let followOnce; let followOnce;

View File

@@ -58,6 +58,9 @@ function JobRenderService ($q, $sce, $window) {
this.setCollapseAll = value => { this.setCollapseAll = value => {
this.state.collapseAll = value; this.state.collapseAll = value;
Object.keys(this.records).forEach(key => {
this.records[key].isCollapsed = value;
});
}; };
this.sortByCounter = (a, b) => { this.sortByCounter = (a, b) => {
@@ -76,7 +79,7 @@ function JobRenderService ($q, $sce, $window) {
// Event Data Transformation / HTML Building // Event Data Transformation / HTML Building
// //
this.transformEventGroup = (events, streaming = false) => { this.appendEventGroup = events => {
let lines = 0; let lines = 0;
let html = ''; let html = '';
@@ -84,16 +87,13 @@ function JobRenderService ($q, $sce, $window) {
for (let i = 0; i <= events.length - 1; i++) { for (let i = 0; i <= events.length - 1; i++) {
const current = events[i]; const current = events[i];
const tailCounter = this.getTailCounter();
if (streaming) { if (tailCounter && (current.counter !== tailCounter + 1)) {
const tailCounter = this.getTailCounter(); const missing = this.appendMissingEventGroup(current);
if (tailCounter && (current.counter !== tailCounter + 1)) { html += missing.html;
const missing = this.transformMissingEventGroup(current); lines += missing.count;
html += missing.html;
lines += missing.count;
}
} }
const line = this.transformEvent(current); const line = this.transformEvent(current);
@@ -105,21 +105,39 @@ function JobRenderService ($q, $sce, $window) {
return { html, lines }; return { html, lines };
}; };
this.transformMissingEventGroup = event => { this.appendMissingEventGroup = event => {
const tail = this.lookupRecord(this.getTailCounter()); const tailCounter = this.getTailCounter();
const tail = this.lookupRecord(tailCounter);
const tailMissing = this.isCounterMissing(tailCounter);
if (!tail || !tail.counter) { if (!tailMissing && (!tail || !tail.counter)) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
const uuid = getUUID(); let uuid;
if (tailMissing) {
uuid = this.missingCounterUUIDs[tailCounter];
} else {
uuid = getUUID();
}
const counters = []; const counters = [];
for (let i = tail.counter + 1; i < event.counter; i++) { for (let i = tailCounter + 1; i < event.counter; i++) {
counters.push(i); if (tailMissing) {
this.missingCounterRecords[uuid].counters.push(i);
} else {
counters.push(i);
}
this.missingCounterUUIDs[i] = uuid; this.missingCounterUUIDs[i] = uuid;
} }
if (tailMissing) {
return { html: '', count: 0 };
}
const record = { const record = {
counters, counters,
uuid, uuid,
@@ -127,6 +145,90 @@ function JobRenderService ($q, $sce, $window) {
end: event.start_line, end: event.start_line,
}; };
if (record.start === record.end) {
return { html: '', count: 0 };
}
this.missingCounterRecords[uuid] = record;
const html = `<div id="${uuid}" class="at-Stdout-row">
<div class="at-Stdout-toggle"></div>
<div class="at-Stdout-line-clickable" ng-click="vm.showMissingEvents('${uuid}')">...</div></div>`;
const count = 1;
return { html, count };
};
this.prependEventGroup = events => {
let lines = 0;
let html = '';
events.sort(this.sortByCounter);
for (let i = events.length - 1; i >= 0; i--) {
const current = events[i];
const headCounter = this.getHeadCounter();
if (headCounter && (current.counter !== headCounter - 1)) {
const missing = this.prependMissingEventGroup(current);
html = missing.html + html;
lines += missing.count;
}
const line = this.transformEvent(current);
html = line.html + html;
lines += line.count;
}
return { html, lines };
};
this.prependMissingEventGroup = event => {
const headCounter = this.getHeadCounter();
const head = this.lookupRecord(headCounter);
const headMissing = this.isCounterMissing(headCounter);
if (!headMissing && (!head || !head.counter)) {
return { html: '', count: 0 };
}
let uuid;
if (headMissing) {
uuid = this.missingCounterUUIDs[headCounter];
} else {
uuid = getUUID();
}
const counters = [];
for (let i = headCounter - 1; i > event.counter; i--) {
if (headMissing) {
this.missingCounterRecords[uuid].counters.unshift(i);
} else {
counters.unshift(i);
}
this.missingCounterUUIDs[i] = uuid;
}
if (headMissing) {
return { html: '', count: 0 };
}
const record = {
counters,
uuid,
start: event.end_line,
end: head.start,
};
if (record.start === record.end) {
return { html: '', count: 0 };
}
this.missingCounterRecords[uuid] = record; this.missingCounterRecords[uuid] = record;
const html = `<div id="${uuid}" class="at-Stdout-row"> const html = `<div id="${uuid}" class="at-Stdout-row">
@@ -401,7 +503,7 @@ function JobRenderService ($q, $sce, $window) {
return $q.resolve(); return $q.resolve();
} }
const result = this.transformEventGroup(events); const result = this.prependEventGroup(events);
const html = this.trustHtml(result.html); const html = this.trustHtml(result.html);
const newElements = angular.element(html); const newElements = angular.element(html);
@@ -411,12 +513,12 @@ function JobRenderService ($q, $sce, $window) {
.then(() => result.lines); .then(() => result.lines);
}; };
this.append = (events, streaming = false) => { this.append = events => {
if (events.length < 1) { if (events.length < 1) {
return $q.resolve(); return $q.resolve();
} }
const result = this.transformEventGroup(events, streaming); const result = this.appendEventGroup(events);
const html = this.trustHtml(result.html); const html = this.trustHtml(result.html);
const newElements = angular.element(html); const newElements = angular.element(html);
@@ -498,10 +600,10 @@ function JobRenderService ($q, $sce, $window) {
return $q.resolve(); return $q.resolve();
}); });
this.pushFront = (events, streaming = false) => { this.pushFront = events => {
const tail = this.getTailCounter(); const tail = this.getTailCounter();
return this.append(events.filter(({ counter }) => counter > tail), streaming); return this.append(events.filter(({ counter }) => counter > tail));
}; };
this.pushBack = events => { this.pushBack = events => {
@@ -511,8 +613,6 @@ function JobRenderService ($q, $sce, $window) {
return this.prepend(events.filter(({ counter }) => counter < head || counter > tail)); return this.prepend(events.filter(({ counter }) => counter < head || counter > tail));
}; };
this.pushFrames = events => this.pushFront(events, true);
this.popMissing = counter => { this.popMissing = counter => {
const uuid = this.missingCounterUUIDs[counter]; const uuid = this.missingCounterUUIDs[counter];

View File

@@ -1,37 +1,9 @@
/* eslint camelcase: 0 */ /* eslint camelcase: 0 */
import { import {
OUTPUT_EVENT_LIMIT, OUTPUT_MAX_BUFFER_LENGTH,
OUTPUT_PAGE_SIZE, OUTPUT_PAGE_SIZE,
} from './constants'; } from './constants';
function getContinuous (events, reverse = false) {
const counters = events.map(({ counter }) => counter);
const min = Math.min(...counters);
const max = Math.max(...counters);
const missing = [];
for (let i = min; i <= max; i++) {
if (counters.indexOf(i) < 0) {
missing.push(i);
}
}
if (missing.length === 0) {
return events;
}
if (reverse) {
const threshold = Math.max(...missing);
return events.filter(({ counter }) => counter > threshold);
}
const threshold = Math.min(...missing);
return events.filter(({ counter }) => counter < threshold);
}
function SlidingWindowService ($q) { function SlidingWindowService ($q) {
this.init = ({ getRange, getFirst, getLast, getMaxCounter }, storage) => { this.init = ({ getRange, getFirst, getLast, getMaxCounter }, storage) => {
const { getHeadCounter, getTailCounter } = storage; const { getHeadCounter, getTailCounter } = storage;
@@ -81,15 +53,13 @@ function SlidingWindowService ($q) {
this.getNext = (displacement = OUTPUT_PAGE_SIZE) => { this.getNext = (displacement = OUTPUT_PAGE_SIZE) => {
const next = this.getNextRange(displacement); const next = this.getNextRange(displacement);
return this.api.getRange(next) return this.api.getRange(next);
.then(results => getContinuous(results));
}; };
this.getPrevious = (displacement = OUTPUT_PAGE_SIZE) => { this.getPrevious = (displacement = OUTPUT_PAGE_SIZE) => {
const previous = this.getPreviousRange(displacement); const previous = this.getPreviousRange(displacement);
return this.api.getRange(previous) return this.api.getRange(previous);
.then(results => getContinuous(results, true));
}; };
this.getFirst = () => { this.getFirst = () => {
@@ -128,7 +98,7 @@ function SlidingWindowService ($q) {
for (let i = frames.length - 1; i >= 0; i--) { for (let i = frames.length - 1; i >= 0; i--) {
count++; count++;
if (count > OUTPUT_EVENT_LIMIT) { if (count > OUTPUT_MAX_BUFFER_LENGTH) {
frames.splice(i, 1); frames.splice(i, 1);
count--; count--;
@@ -153,29 +123,25 @@ function SlidingWindowService ($q) {
return frames; return frames;
} }
if (min >= head && min <= tail + 1) { return frames.filter(({ counter }) => counter > tail);
return frames.filter(({ counter }) => counter > tail);
}
return [];
}; };
this.getFrames = () => $q.resolve(this.buffer.events); this.getFrames = () => $q.resolve(this.buffer.events);
this.getMaxCounter = () => { this.getMaxCounter = () => {
if (this.buffer.min && this.buffer.min > 1) { if (this.buffer.max && this.buffer.max > 1) {
return this.buffer.min - 1; return this.buffer.max;
} }
return this.api.getMaxCounter(); return this.api.getMaxCounter();
}; };
this.isOnLastPage = () => { this.isOnLastPage = () => {
if (this.getTailCounter() === 0) { if (this.buffer.min) {
return true; return this.getTailCounter() >= this.buffer.min - 1;
} }
return this.getTailCounter() >= (this.getMaxCounter() - OUTPUT_PAGE_SIZE); return this.getTailCounter() >= this.getMaxCounter() - OUTPUT_PAGE_SIZE;
}; };
this.isOnFirstPage = () => this.getHeadCounter() === 1; this.isOnFirstPage = () => this.getHeadCounter() === 1;