diff --git a/awx/ui/client/features/output/index.controller.js b/awx/ui/client/features/output/index.controller.js index 9021108a30..d826fdbcc2 100644 --- a/awx/ui/client/features/output/index.controller.js +++ b/awx/ui/client/features/output/index.controller.js @@ -4,7 +4,6 @@ import hasAnsi from 'has-ansi'; let vm; let ansi; let job; -let jobEvent; let container; let $timeout; let $sce; @@ -18,7 +17,6 @@ const meta = { page: {} }; -const ROW_LIMIT = 200; const PAGE_LIMIT = 3; const SCROLL_BUFFER = 250; const SCROLL_LOAD_DELAY = 250; @@ -41,7 +39,6 @@ const TIME_EVENTS = [ function JobsIndexController ( _job_, - JobEventModel, _$sce_, _$timeout_, _$scope_, @@ -56,10 +53,10 @@ function JobsIndexController ( job = _job_; ansi = new Ansi(); - jobEvent = new JobEventModel(); const events = job.get('related.job_events.results'); - const html = $sce.trustAsHtml(parseEvents(events)); + const parsed = parseEvents(events); + const html = $sce.trustAsHtml(parsed.html); vm = this || {}; @@ -87,7 +84,7 @@ function JobsIndexController ( meta.page.cache = [{ page: 1, - count: events.length + lines: parsed.lines }]; $timeout(() => { @@ -118,11 +115,9 @@ function next () { } meta.page.cache.push({ - page: data.page, - count: data.results.length + page: data.page }); - console.log(data.results); return shift() .then(() => append(data.results)); }); @@ -138,7 +133,6 @@ function prev () { }; console.log('[2] getting previous page', config.page, meta.page.cache); - return job.goToPage(config) .then(data => { if (!data || !data.results) { @@ -146,8 +140,7 @@ function prev () { } meta.page.cache.unshift({ - page: data.page, - count: data.results.length + page: data.page }); return pop() @@ -202,8 +195,12 @@ function append (events) { console.log('[4] appending next page'); return $q(resolve => { - const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parseEvents(events)))); + const parsed = parseEvents(events); + const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parsed.html))); const table = $(ELEMENT_TBODY); + const index = meta.page.cache.length - 1; + + meta.page.cache[index].lines = parsed.lines; table.append(rows); $compile(rows.contents())($scope); @@ -217,12 +214,11 @@ function prepend (events) { console.log('[4] prepending next page'); return $q(resolve => { - const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parseEvents(events)))); + const parsed = parseEvents(events); + const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parsed.html))); const table = $(ELEMENT_TBODY); - // Set row count added - // pop number of rows (not number of events) - // meta.page.cache[0].rows = rows.length; + meta.page.cache[0].lines = parsed.lines; table.prepend(rows); $compile(rows.contents())($scope); @@ -243,7 +239,7 @@ function pop () { const ejected = meta.page.cache.pop(); console.log('[3.1] popping', ejected); - const rows = $(ELEMENT_TBODY).children().slice(-ejected.count); + const rows = $(ELEMENT_TBODY).children().slice(-ejected.lines); rows.empty(); rows.remove(); @@ -264,7 +260,7 @@ function shift () { const ejected = meta.page.cache.shift(); console.log('[3.1] shifting', ejected); - const rows = $(ELEMENT_TBODY).children().slice(0, ejected.count); + const rows = $(ELEMENT_TBODY).children().slice(0, ejected.lines); rows.empty(); rows.remove(); @@ -288,9 +284,22 @@ function scrollTo (direction) { } function parseEvents (events) { + let lines = 0; + let html = ''; + events.sort(orderByLineNumber); - return events.reduce((html, event) => `${html}${parseLine(event)}`, ''); + events.forEach(event => { + const line = parseLine(event); + + html += line.html; + lines += line.count; + }); + + return { + html, + lines + }; } function orderByLineNumber (a, b) { @@ -307,17 +316,18 @@ function orderByLineNumber (a, b) { function parseLine (event) { if (!event || !event.stdout) { - return ''; + return { html: '', count: 0 }; } const { stdout } = event; const lines = stdout.split('\r\n'); + let count = lines.length; let ln = event.start_line; const current = createRecord(ln, lines, event); - return lines.reduce((html, line, i) => { + const html = lines.reduce((html, line, i) => { ln++; const isLastLine = i === lines.length - 1; @@ -325,10 +335,13 @@ function parseLine (event) { if (current && current.isTruncated && isLastLine) { row += createRow(current); + count++; } return `${html}${row}`; }, ''); + + return { html, count }; } function createRecord (ln, lines, event) { @@ -541,7 +554,6 @@ function onScroll () { JobsIndexController.$inject = [ 'job', - 'JobEventModel', '$sce', '$timeout', '$scope', diff --git a/awx/ui/client/features/output/index.js b/awx/ui/client/features/output/index.js index e8daf39557..d447ed2817 100644 --- a/awx/ui/client/features/output/index.js +++ b/awx/ui/client/features/output/index.js @@ -10,10 +10,48 @@ const indexTemplate = require('~features/output/index.view.html'); const MODULE_NAME = 'at.features.output'; +function resolveJob (Job, ProjectUpdate, AdHocCommand, SystemJob, WorkflowJob, $stateParams) { + const { id } = $stateParams; + const { type } = $stateParams; + + let Resource; + + switch (type) { + case 'project': + Resource = ProjectUpdate; + break; + case 'playbook': + Resource = Job; + break; + case 'command': + Resource = AdHocCommand; + break; + case 'system': + Resource = SystemJob; + break; + case 'workflow': + Resource = WorkflowJob; + break; + default: + // Redirect + return null; + } + + return new Resource('get', id) + .then(resource => resource.extend('job_events', { + pageCache: true, + pageLimit: 3, + params: { + page_size: 100, + order_by: 'start_line' + } + })); +} + function JobsRun ($stateExtender, strings) { $stateExtender.addState({ name: 'jobz', - route: '/jobz/:id', + route: '/jobz/:type/:id', ncyBreadcrumb: { label: strings.get('state.TITLE') }, @@ -29,19 +67,15 @@ function JobsRun ($stateExtender, strings) { } }, resolve: { - job: ['JobModel', '$stateParams', (Jobs, $stateParams) => { - const { id } = $stateParams; - - return new Jobs('get', id) - .then(job => job.extend('job_events', { - pageCache: true, - pageLimit: 3, - params: { - page_size: 100, - order_by: 'start_line' - }, - })); - }] + job: [ + 'JobModel', + 'ProjectUpdateModel', + 'AdHocCommandModel', + 'SystemJobModel', + 'WorkflowJobModel', + '$stateParams', + resolveJob + ] } }); } diff --git a/awx/ui/client/lib/models/AdHocCommand.js b/awx/ui/client/lib/models/AdHocCommand.js index c398219531..9f259a929a 100644 --- a/awx/ui/client/lib/models/AdHocCommand.js +++ b/awx/ui/client/lib/models/AdHocCommand.js @@ -1,5 +1,5 @@ -let Base; let $http; +let BaseModel; function getRelaunch (params) { const req = { @@ -20,7 +20,7 @@ function postRelaunch (params) { } function AdHocCommandModel (method, resource, config) { - Base.call(this, 'ad_hoc_commands'); + BaseModel.call(this, 'ad_hoc_commands'); this.Constructor = AdHocCommandModel; this.postRelaunch = postRelaunch.bind(this); @@ -29,16 +29,16 @@ function AdHocCommandModel (method, resource, config) { return this.create(method, resource, config); } -function AdHocCommandModelLoader (BaseModel, _$http_) { - Base = BaseModel; +function AdHocCommandModelLoader (_$http_, _BaseModel_) { $http = _$http_; + BaseModel = _BaseModel_; return AdHocCommandModel; } AdHocCommandModelLoader.$inject = [ + '$http', 'BaseModel', - '$http' ]; export default AdHocCommandModelLoader; diff --git a/awx/ui/client/lib/models/Base.js b/awx/ui/client/lib/models/Base.js index 0c04964a5f..9985de8799 100644 --- a/awx/ui/client/lib/models/Base.js +++ b/awx/ui/client/lib/models/Base.js @@ -460,8 +460,6 @@ function goToPage (config) { return $http(req) .then(({ data }) => { - let ejected; - if (pageCache) { pageCache[pageNumber] = data.results; pagesInCache.push(pageNumber); @@ -469,7 +467,9 @@ function goToPage (config) { if (pagesInCache.length > this.page.limit) { const pageToDelete = pagesInCache.shift(); + console.log(pageCache); delete pageCache[pageToDelete]; + console.log(this.page.cache); } } diff --git a/awx/ui/client/lib/models/ProjectUpdate.js b/awx/ui/client/lib/models/ProjectUpdate.js new file mode 100644 index 0000000000..3de76790df --- /dev/null +++ b/awx/ui/client/lib/models/ProjectUpdate.js @@ -0,0 +1,19 @@ +let BaseModel; + +function ProjectUpdateModel (method, resource, config) { + BaseModel.call(this, 'jobs'); + + this.Constructor = ProjectUpdateModel; + + return this.create(method, resource, config); +} + +function ProjectUpdateModelLoader (_BaseModel_) { + BaseModel = _BaseModel_; + + return ProjectUpdateModel; +} + +ProjectUpdateModelLoader.$inject = ['BaseModel']; + +export default ProjectUpdateModelLoader; diff --git a/awx/ui/client/lib/models/SystemJob.js b/awx/ui/client/lib/models/SystemJob.js new file mode 100644 index 0000000000..ec41941046 --- /dev/null +++ b/awx/ui/client/lib/models/SystemJob.js @@ -0,0 +1,19 @@ +let BaseModel; + +function SystemJobModel (method, resource, config) { + BaseModel.call(this, 'jobs'); + + this.Constructor = SystemJobModel; + + return this.create(method, resource, config); +} + +function SystemJobModelLoader (_BaseModel_) { + BaseModel = _BaseModel_; + + return SystemJobModel; +} + +SystemJobModelLoader.$inject = ['BaseModel']; + +export default SystemJobModelLoader; diff --git a/awx/ui/client/lib/models/index.js b/awx/ui/client/lib/models/index.js index 91eb3742ee..3875975d4d 100644 --- a/awx/ui/client/lib/models/index.js +++ b/awx/ui/client/lib/models/index.js @@ -14,12 +14,13 @@ import InventorySource from '~models/InventorySource'; import Job from '~models/Job'; import JobEvent from '~models/JobEvent'; import JobTemplate from '~models/JobTemplate'; -import Jobs from '~models/Jobs'; import Me from '~models/Me'; import NotificationTemplate from '~models/NotificationTemplate'; import Organization from '~models/Organization'; import Project from '~models/Project'; import Schedule from '~models/Schedule'; +import ProjectUpdate from '~models/ProjectUpdate'; +import SystemJob from '~models/SystemJob'; import UnifiedJobTemplate from '~models/UnifiedJobTemplate'; import WorkflowJob from '~models/WorkflowJob'; import WorkflowJobTemplate from '~models/WorkflowJobTemplate'; @@ -48,18 +49,18 @@ angular .service('JobEventModel', JobEvent) .service('JobModel', Job) .service('JobTemplateModel', JobTemplate) - .service('JobsModel', Jobs) .service('MeModel', Me) .service('NotificationTemplate', NotificationTemplate) .service('OrganizationModel', Organization) .service('ProjectModel', Project) .service('ScheduleModel', Schedule) .service('UnifiedJobModel', UnifiedJob) + .service('ProjectUpdateModel', ProjectUpdate) + .service('SystemJobModel', SystemJob) .service('UnifiedJobTemplateModel', UnifiedJobTemplate) .service('WorkflowJobModel', WorkflowJob) .service('WorkflowJobTemplateModel', WorkflowJobTemplate) .service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode) - .service('WorkflowJobTemplateNodeModel', WorkflowJobTemplateNode) .service('ModelsStrings', ModelsStrings); export default MODULE_NAME;