diff --git a/awx/ui/client/features/output/render.service.js b/awx/ui/client/features/output/render.service.js index 7d98a1be2c..520324866f 100644 --- a/awx/ui/client/features/output/render.service.js +++ b/awx/ui/client/features/output/render.service.js @@ -1,6 +1,5 @@ import Ansi from 'ansi-to-html'; import Entities from 'html-entities'; -import getUUID from 'uuid'; import { EVENT_START_PLAY, @@ -36,24 +35,18 @@ const hasAnsi = input => re.test(input); function JobRenderService ($q, $sce, $window) { this.init = ({ compile, toggles }) => { this.hooks = { compile }; - this.el = $(OUTPUT_ELEMENT_TBODY); this.parent = null; this.state = { - head: null, - tail: null, + head: 0, + tail: 0, collapseAll: false, toggleMode: toggles, }; - this.counters = {}; - this.lines = {}; this.records = {}; this.uuids = {}; - - this.missingCounterRecords = {}; - this.missingCounterUUIDs = {}; }; this.setCollapseAll = value => { @@ -87,73 +80,54 @@ function JobRenderService ($q, $sce, $window) { for (let i = 0; i <= events.length - 1; 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); html += missing.html; lines += missing.count; } - const line = this.transformEvent(current); + const eventLines = this.transformEvent(current); - html += line.html; - lines += line.count; + html += eventLines.html; + lines += eventLines.count; } return { html, lines }; }; this.appendMissingEventGroup = event => { - const tailCounter = this.getTailCounter(); - const tail = this.lookupRecord(tailCounter); - const tailMissing = this.isCounterMissing(tailCounter); + const tailUUID = this.uuids[this.state.tail]; + const tailRecord = this.records[tailUUID]; - if (!tailMissing && (!tail || !tail.counter)) { + if (!tailRecord) { return { html: '', count: 0 }; } let uuid; - if (tailMissing) { - uuid = this.missingCounterUUIDs[tailCounter]; + if (tailRecord.isMissing) { + uuid = tailUUID; } else { - uuid = getUUID(); + uuid = `${event.counter}-${tailUUID}`; + this.records[uuid] = { uuid, counters: [], lineCount: 1, isMissing: true }; } - const counters = []; - - for (let i = tailCounter + 1; i < event.counter; i++) { - if (tailMissing) { - this.missingCounterRecords[uuid].counters.push(i); - } else { - counters.push(i); - } - - this.missingCounterUUIDs[i] = uuid; + for (let i = this.state.tail + 1; i < event.counter; i++) { + this.records[uuid].counters.push(i); + this.uuids[i] = uuid; } - if (tailMissing) { + if (tailRecord.isMissing) { return { html: '', count: 0 }; } - const record = { - counters, - uuid, - start: tail.end, - end: event.start_line, - }; - - if (record.start === record.end) { + if (tailRecord.end === event.start_line) { return { html: '', count: 0 }; } - this.missingCounterRecords[uuid] = record; - - const html = `
-
-
...
`; + const html = this.buildRowHTML(this.records[uuid]); const count = 1; return { html, count }; @@ -167,84 +141,65 @@ function JobRenderService ($q, $sce, $window) { for (let i = events.length - 1; i >= 0; 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); html = missing.html + html; lines += missing.count; } - const line = this.transformEvent(current); + const eventLines = this.transformEvent(current); - html = line.html + html; - lines += line.count; + html = eventLines.html + html; + lines += eventLines.count; } return { html, lines }; }; this.prependMissingEventGroup = event => { - const headCounter = this.getHeadCounter(); - const head = this.lookupRecord(headCounter); - const headMissing = this.isCounterMissing(headCounter); + const headUUID = this.uuids[this.state.head]; + const headRecord = this.records[headUUID]; - if (!headMissing && (!head || !head.counter)) { + if (!headRecord) { return { html: '', count: 0 }; } let uuid; - if (headMissing) { - uuid = this.missingCounterUUIDs[headCounter]; + if (headRecord.isMissing) { + uuid = headUUID; } else { - uuid = getUUID(); + uuid = `${headUUID}-${event.counter}`; + this.records[uuid] = { uuid, counters: [], lineCount: 1, isMissing: true }; } - 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; + for (let i = this.state.head - 1; i > event.counter; i--) { + this.records[uuid].counters.unshift(i); + this.uuids[i] = uuid; } - if (headMissing) { + if (headRecord.isMissing) { return { html: '', count: 0 }; } - const record = { - counters, - uuid, - start: event.end_line, - end: head.start, - }; - - if (record.start === record.end) { + if (event.end_line === headRecord.start) { return { html: '', count: 0 }; } - this.missingCounterRecords[uuid] = record; - - const html = `
-
-
...
`; + const html = this.buildRowHTML(this.records[uuid]); const count = 1; return { html, count }; }; this.transformEvent = event => { - if (event.uuid && this.records[event.uuid]) { + if (!event || !event.stdout) { return { html: '', count: 0 }; } - if (!event || !event.stdout) { + if (event.uuid && this.records[event.uuid]) { return { html: '', count: 0 }; } @@ -262,10 +217,10 @@ function JobRenderService ($q, $sce, $window) { const line = lines[i]; 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) { - row += this.createRow(record); + row += this.buildRowHTML(record); count++; } @@ -280,20 +235,19 @@ function JobRenderService ($q, $sce, $window) { return null; } - this.lines[event.counter] = event.end_line - event.start_line; - - 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) { + if (!this.state.head || event.counter < this.state.head) { this.state.head = event.counter; } + if (!this.state.tail || event.counter > this.state.tail) { + this.state.tail = event.counter; + } + 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; @@ -317,7 +271,7 @@ function JobRenderService ($q, $sce, $window) { isTruncated: (event.end_line - event.start_line) > lines.length, lineCount: lines.length, isCollapsed: this.state.collapseAll, - counter: event.counter, + counters: [event.counter], }; if (event.parent_uuid) { @@ -355,9 +309,8 @@ function JobRenderService ($q, $sce, $window) { record.line++; } - this.uuids[event.counter] = record.uuid; - this.counters[event.uuid] = record.counter; this.records[event.uuid] = record; + this.uuids[event.counter] = event.uuid; return record; }; @@ -374,25 +327,7 @@ function JobRenderService ($q, $sce, $window) { return list; }; - this.deleteRecord = counter => { - 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) => { + this.buildRowHTML = (record, ln, content) => { let id = ''; let icon = ''; let timestamp = ''; @@ -400,6 +335,12 @@ function JobRenderService ($q, $sce, $window) { let tdEvent = ''; let classList = ''; + if (record.isMissing) { + return `
+
+
...
`; + } + content = content || ''; if (hasAnsi(content)) { @@ -459,6 +400,15 @@ function JobRenderService ($q, $sce, $window) { `; }; + 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 // @@ -532,70 +482,25 @@ function JobRenderService ($q, $sce, $window) { 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() .then(() => { const head = this.getHeadCounter(); const tail = this.getTailCounter(); for (let i = head; i <= tail; ++i) { - this.deleteRecord(i); - this.deleteMissingCounterRecord(i); + const uuid = this.uuids[i]; + + if (uuid) { + delete this.records[uuid]; + delete this.uuids[i]; + } } - this.state.head = null; - this.state.tail = null; + this.state.head = 0; + this.state.tail = 0; return $q.resolve(); }); @@ -613,73 +518,35 @@ function JobRenderService ($q, $sce, $window) { 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 => { if (!count || count <= 0) { return $q.resolve(); } - const max = this.getTailCounter(); + const max = this.state.tail; const min = max - count; let lines = 0; for (let i = max; i >= min; --i) { - if (this.isCounterMissing(i)) { - lines += this.popMissing(i); - } else { - lines += this.getLineCount(i); + const uuid = this.uuids[i]; + + if (!uuid) { + 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) - .then(() => { - for (let i = max; i >= min; --i) { - this.deleteRecord(i); - this.state.tail--; - } - - return $q.resolve(); - }); + return this.pop(lines); }; this.popBack = count => { @@ -687,29 +554,35 @@ function JobRenderService ($q, $sce, $window) { return $q.resolve(); } - const min = this.getHeadCounter(); + const min = this.state.head; const max = min + count; let lines = 0; for (let i = min; i <= max; ++i) { - if (this.isCounterMissing(i)) { - lines += this.popMissing(i); - } else { - lines += this.getLineCount(i); + const uuid = this.uuids[i]; + + if (!uuid) { + 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) - .then(() => { - for (let i = min; i <= max; ++i) { - this.deleteRecord(i); - this.state.head++; - } - - return $q.resolve(); - }); + return this.shift(lines); }; + + this.getHeadCounter = () => this.state.head; + this.getTailCounter = () => this.state.tail; + this.getCapacity = () => OUTPUT_EVENT_LIMIT - (this.getTailCounter() - this.getHeadCounter()); } JobRenderService.$inject = ['$q', '$sce', '$window'];