refactor render service

This commit is contained in:
Jake McDermott
2018-08-25 00:57:50 -04:00
parent 04dbc2fcc4
commit d608402dc1

View File

@@ -1,6 +1,5 @@
import Ansi from 'ansi-to-html'; import Ansi from 'ansi-to-html';
import Entities from 'html-entities'; import Entities from 'html-entities';
import getUUID from 'uuid';
import { import {
EVENT_START_PLAY, EVENT_START_PLAY,
@@ -36,24 +35,18 @@ const hasAnsi = input => re.test(input);
function JobRenderService ($q, $sce, $window) { function JobRenderService ($q, $sce, $window) {
this.init = ({ compile, toggles }) => { this.init = ({ compile, toggles }) => {
this.hooks = { compile }; this.hooks = { compile };
this.el = $(OUTPUT_ELEMENT_TBODY); this.el = $(OUTPUT_ELEMENT_TBODY);
this.parent = null; this.parent = null;
this.state = { this.state = {
head: null, head: 0,
tail: null, tail: 0,
collapseAll: false, collapseAll: false,
toggleMode: toggles, toggleMode: toggles,
}; };
this.counters = {};
this.lines = {};
this.records = {}; this.records = {};
this.uuids = {}; this.uuids = {};
this.missingCounterRecords = {};
this.missingCounterUUIDs = {};
}; };
this.setCollapseAll = value => { this.setCollapseAll = value => {
@@ -87,73 +80,54 @@ 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 (tailCounter && (current.counter !== tailCounter + 1)) { if (this.state.tail && current.counter !== this.state.tail + 1) {
const missing = this.appendMissingEventGroup(current); const missing = this.appendMissingEventGroup(current);
html += missing.html; html += missing.html;
lines += missing.count; lines += missing.count;
} }
const line = this.transformEvent(current); const eventLines = this.transformEvent(current);
html += line.html; html += eventLines.html;
lines += line.count; lines += eventLines.count;
} }
return { html, lines }; return { html, lines };
}; };
this.appendMissingEventGroup = event => { this.appendMissingEventGroup = event => {
const tailCounter = this.getTailCounter(); const tailUUID = this.uuids[this.state.tail];
const tail = this.lookupRecord(tailCounter); const tailRecord = this.records[tailUUID];
const tailMissing = this.isCounterMissing(tailCounter);
if (!tailMissing && (!tail || !tail.counter)) { if (!tailRecord) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
let uuid; let uuid;
if (tailMissing) { if (tailRecord.isMissing) {
uuid = this.missingCounterUUIDs[tailCounter]; uuid = tailUUID;
} else { } else {
uuid = getUUID(); uuid = `${event.counter}-${tailUUID}`;
this.records[uuid] = { uuid, counters: [], lineCount: 1, isMissing: true };
} }
const counters = []; for (let i = this.state.tail + 1; i < event.counter; i++) {
this.records[uuid].counters.push(i);
for (let i = tailCounter + 1; i < event.counter; i++) { this.uuids[i] = uuid;
if (tailMissing) {
this.missingCounterRecords[uuid].counters.push(i);
} else {
counters.push(i);
}
this.missingCounterUUIDs[i] = uuid;
} }
if (tailMissing) { if (tailRecord.isMissing) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
const record = { if (tailRecord.end === event.start_line) {
counters,
uuid,
start: tail.end,
end: event.start_line,
};
if (record.start === record.end) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
this.missingCounterRecords[uuid] = record; const html = this.buildRowHTML(this.records[uuid]);
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; const count = 1;
return { html, count }; return { html, count };
@@ -167,84 +141,65 @@ function JobRenderService ($q, $sce, $window) {
for (let i = events.length - 1; i >= 0; i--) { for (let i = events.length - 1; i >= 0; i--) {
const current = events[i]; const current = events[i];
const headCounter = this.getHeadCounter();
if (headCounter && (current.counter !== headCounter - 1)) { if (this.state.head && current.counter !== this.state.head - 1) {
const missing = this.prependMissingEventGroup(current); const missing = this.prependMissingEventGroup(current);
html = missing.html + html; html = missing.html + html;
lines += missing.count; lines += missing.count;
} }
const line = this.transformEvent(current); const eventLines = this.transformEvent(current);
html = line.html + html; html = eventLines.html + html;
lines += line.count; lines += eventLines.count;
} }
return { html, lines }; return { html, lines };
}; };
this.prependMissingEventGroup = event => { this.prependMissingEventGroup = event => {
const headCounter = this.getHeadCounter(); const headUUID = this.uuids[this.state.head];
const head = this.lookupRecord(headCounter); const headRecord = this.records[headUUID];
const headMissing = this.isCounterMissing(headCounter);
if (!headMissing && (!head || !head.counter)) { if (!headRecord) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
let uuid; let uuid;
if (headMissing) { if (headRecord.isMissing) {
uuid = this.missingCounterUUIDs[headCounter]; uuid = headUUID;
} else { } else {
uuid = getUUID(); uuid = `${headUUID}-${event.counter}`;
this.records[uuid] = { uuid, counters: [], lineCount: 1, isMissing: true };
} }
const counters = []; for (let i = this.state.head - 1; i > event.counter; i--) {
this.records[uuid].counters.unshift(i);
for (let i = headCounter - 1; i > event.counter; i--) { this.uuids[i] = uuid;
if (headMissing) {
this.missingCounterRecords[uuid].counters.unshift(i);
} else {
counters.unshift(i);
}
this.missingCounterUUIDs[i] = uuid;
} }
if (headMissing) { if (headRecord.isMissing) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
const record = { if (event.end_line === headRecord.start) {
counters,
uuid,
start: event.end_line,
end: head.start,
};
if (record.start === record.end) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
this.missingCounterRecords[uuid] = record; const html = this.buildRowHTML(this.records[uuid]);
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; const count = 1;
return { html, count }; return { html, count };
}; };
this.transformEvent = event => { this.transformEvent = event => {
if (event.uuid && this.records[event.uuid]) { if (!event || !event.stdout) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
if (!event || !event.stdout) { if (event.uuid && this.records[event.uuid]) {
return { html: '', count: 0 }; return { html: '', count: 0 };
} }
@@ -262,10 +217,10 @@ function JobRenderService ($q, $sce, $window) {
const line = lines[i]; const line = lines[i];
const isLastLine = i === lines.length - 1; const isLastLine = i === lines.length - 1;
let row = this.createRow(record, ln, line); let row = this.buildRowHTML(record, ln, line);
if (record && record.isTruncated && isLastLine) { if (record && record.isTruncated && isLastLine) {
row += this.createRow(record); row += this.buildRowHTML(record);
count++; count++;
} }
@@ -280,20 +235,19 @@ function JobRenderService ($q, $sce, $window) {
return null; return null;
} }
this.lines[event.counter] = event.end_line - event.start_line; if (!this.state.head || event.counter < this.state.head) {
if (this.state.tail === null ||
this.state.tail < event.counter) {
this.state.tail = event.counter;
}
if (this.state.head === null ||
this.state.head > event.counter) {
this.state.head = event.counter; this.state.head = event.counter;
} }
if (!this.state.tail || event.counter > this.state.tail) {
this.state.tail = event.counter;
}
if (!event.uuid) { if (!event.uuid) {
return null; this.uuids[event.counter] = event.counter;
this.records[event.counter] = { counters: [event.counter], lineCount: lines.length };
return this.records[event.counter];
} }
let isHost = false; let isHost = false;
@@ -317,7 +271,7 @@ function JobRenderService ($q, $sce, $window) {
isTruncated: (event.end_line - event.start_line) > lines.length, isTruncated: (event.end_line - event.start_line) > lines.length,
lineCount: lines.length, lineCount: lines.length,
isCollapsed: this.state.collapseAll, isCollapsed: this.state.collapseAll,
counter: event.counter, counters: [event.counter],
}; };
if (event.parent_uuid) { if (event.parent_uuid) {
@@ -355,9 +309,8 @@ function JobRenderService ($q, $sce, $window) {
record.line++; record.line++;
} }
this.uuids[event.counter] = record.uuid;
this.counters[event.uuid] = record.counter;
this.records[event.uuid] = record; this.records[event.uuid] = record;
this.uuids[event.counter] = event.uuid;
return record; return record;
}; };
@@ -374,25 +327,7 @@ function JobRenderService ($q, $sce, $window) {
return list; return list;
}; };
this.deleteRecord = counter => { this.buildRowHTML = (record, ln, content) => {
const uuid = this.uuids[counter];
delete this.records[uuid];
delete this.counters[uuid];
delete this.uuids[counter];
delete this.lines[counter];
};
this.getTimestamp = created => {
const date = new Date(created);
const hour = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours();
const minute = date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes();
const second = date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds();
return `${hour}:${minute}:${second}`;
};
this.createRow = (record, ln, content) => {
let id = ''; let id = '';
let icon = ''; let icon = '';
let timestamp = ''; let timestamp = '';
@@ -400,6 +335,12 @@ function JobRenderService ($q, $sce, $window) {
let tdEvent = ''; let tdEvent = '';
let classList = ''; let classList = '';
if (record.isMissing) {
return `<div id="${record.uuid}" class="at-Stdout-row">
<div class="at-Stdout-toggle"></div>
<div class="at-Stdout-line-clickable" ng-click="vm.showMissingEvents('${record.uuid}')">...</div></div>`;
}
content = content || ''; content = content || '';
if (hasAnsi(content)) { if (hasAnsi(content)) {
@@ -459,6 +400,15 @@ function JobRenderService ($q, $sce, $window) {
</div>`; </div>`;
}; };
this.getTimestamp = created => {
const date = new Date(created);
const hour = date.getHours() < 10 ? `0${date.getHours()}` : date.getHours();
const minute = date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes();
const second = date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds();
return `${hour}:${minute}:${second}`;
};
// //
// Element Operations // Element Operations
// //
@@ -532,70 +482,25 @@ function JobRenderService ($q, $sce, $window) {
this.sanitize = html => entities.encode(html); this.sanitize = html => entities.encode(html);
// //
// Event Counter Methods - External code should use these. // Event Counter Methods - External code should prefer these.
// //
this.getTailCounter = () => {
if (this.state.tail === null) {
return 0;
}
if (this.state.tail < 0) {
return 0;
}
return this.state.tail;
};
this.getHeadCounter = () => {
if (this.state.head === null) {
return 0;
}
if (this.state.head < 0) {
return 0;
}
return this.state.head;
};
this.getCapacity = () => OUTPUT_EVENT_LIMIT - Object.keys(this.lines).length;
this.lookupRecord = counter => this.records[this.uuids[counter]];
this.getLineCount = counter => {
const record = this.lookupRecord(counter);
if (record && record.lineCount) {
return record.lineCount;
}
if (this.lines[counter]) {
return this.lines[counter];
}
return 0;
};
this.deleteMissingCounterRecord = counter => {
const uuid = this.missingCounterUUIDs[counter];
delete this.missingCounterRecords[counter];
delete this.missingCounterUUIDs[uuid];
};
this.clear = () => this.removeAll() this.clear = () => this.removeAll()
.then(() => { .then(() => {
const head = this.getHeadCounter(); const head = this.getHeadCounter();
const tail = this.getTailCounter(); const tail = this.getTailCounter();
for (let i = head; i <= tail; ++i) { for (let i = head; i <= tail; ++i) {
this.deleteRecord(i); const uuid = this.uuids[i];
this.deleteMissingCounterRecord(i);
if (uuid) {
delete this.records[uuid];
delete this.uuids[i];
}
} }
this.state.head = null; this.state.head = 0;
this.state.tail = null; this.state.tail = 0;
return $q.resolve(); return $q.resolve();
}); });
@@ -613,73 +518,35 @@ 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.popMissing = counter => {
const uuid = this.missingCounterUUIDs[counter];
if (!this.missingCounterRecords[uuid]) {
return 0;
}
this.missingCounterRecords[uuid].counters.pop();
if (this.missingCounterRecords[uuid].counters.length > 0) {
return 0;
}
delete this.missingCounterRecords[uuid];
delete this.missingCounterUUIDs[counter];
return 1;
};
this.shiftMissing = counter => {
const uuid = this.missingCounterUUIDs[counter];
if (!this.missingCounterRecords[uuid]) {
return 0;
}
this.missingCounterRecords[uuid].counters.shift();
if (this.missingCounterRecords[uuid].counters.length > 0) {
return 0;
}
delete this.missingCounterRecords[uuid];
delete this.missingCounterUUIDs[counter];
return 1;
};
this.isCounterMissing = counter => this.missingCounterUUIDs[counter];
this.popFront = count => { this.popFront = count => {
if (!count || count <= 0) { if (!count || count <= 0) {
return $q.resolve(); return $q.resolve();
} }
const max = this.getTailCounter(); const max = this.state.tail;
const min = max - count; const min = max - count;
let lines = 0; let lines = 0;
for (let i = max; i >= min; --i) { for (let i = max; i >= min; --i) {
if (this.isCounterMissing(i)) { const uuid = this.uuids[i];
lines += this.popMissing(i);
} else { if (!uuid) {
lines += this.getLineCount(i); continue;
}
this.records[uuid].counters.pop();
delete this.uuids[i];
if (this.records[uuid].counters.length === 0) {
lines += this.records[uuid].lineCount;
delete this.records[uuid];
this.state.tail--;
} }
} }
return this.pop(lines) return this.pop(lines);
.then(() => {
for (let i = max; i >= min; --i) {
this.deleteRecord(i);
this.state.tail--;
}
return $q.resolve();
});
}; };
this.popBack = count => { this.popBack = count => {
@@ -687,29 +554,35 @@ function JobRenderService ($q, $sce, $window) {
return $q.resolve(); return $q.resolve();
} }
const min = this.getHeadCounter(); const min = this.state.head;
const max = min + count; const max = min + count;
let lines = 0; let lines = 0;
for (let i = min; i <= max; ++i) { for (let i = min; i <= max; ++i) {
if (this.isCounterMissing(i)) { const uuid = this.uuids[i];
lines += this.popMissing(i);
} else { if (!uuid) {
lines += this.getLineCount(i); continue;
}
this.records[uuid].counters.shift();
delete this.uuids[i];
if (this.records[uuid].counters.length === 0) {
lines += this.records[uuid].lineCount;
delete this.records[uuid];
this.state.head++;
} }
} }
return this.shift(lines) return this.shift(lines);
.then(() => {
for (let i = min; i <= max; ++i) {
this.deleteRecord(i);
this.state.head++;
}
return $q.resolve();
});
}; };
this.getHeadCounter = () => this.state.head;
this.getTailCounter = () => this.state.tail;
this.getCapacity = () => OUTPUT_EVENT_LIMIT - (this.getTailCounter() - this.getHeadCounter());
} }
JobRenderService.$inject = ['$q', '$sce', '$window']; JobRenderService.$inject = ['$q', '$sce', '$window'];