From cc36ee6bedd03fac1814b1fbbc361d905b37817c Mon Sep 17 00:00:00 2001 From: gconsidine Date: Tue, 23 Jan 2018 17:05:59 -0500 Subject: [PATCH] Add WIP prepend/previous on scroll --- .../features/output/index.controller.js | 161 +++++++++++++----- awx/ui/client/features/output/index.js | 4 +- awx/ui/client/lib/models/Base.js | 159 ++++++----------- 3 files changed, 172 insertions(+), 152 deletions(-) diff --git a/awx/ui/client/features/output/index.controller.js b/awx/ui/client/features/output/index.controller.js index dcfabe4d7a..3fa2686c08 100644 --- a/awx/ui/client/features/output/index.controller.js +++ b/awx/ui/client/features/output/index.controller.js @@ -10,6 +10,7 @@ let $timeout; let $sce; let $compile; let $scope; +let $q; const record = {}; const meta = { @@ -18,7 +19,7 @@ const meta = { const ROW_LIMIT = 200; const SCROLL_BUFFER = 250; -const SCROLL_LOAD_DELAY = 100; +// const SCROLL_LOAD_DELAY = 100; const EVENT_START_TASK = 'playbook_on_task_start'; const EVENT_START_PLAY = 'playbook_on_play_start'; const EVENT_STATS_PLAY = 'playbook_on_stats'; @@ -36,11 +37,20 @@ const TIME_EVENTS = [ EVENT_STATS_PLAY ]; -function JobsIndexController (_job_, JobEventModel, _$sce_, _$timeout_, _$scope_, _$compile_) { +function JobsIndexController ( + _job_, + JobEventModel, + _$sce_, + _$timeout_, + _$scope_, + _$compile_, + _$q_ +) { $timeout = _$timeout_; $sce = _$sce_; $compile = _$compile_; $scope = _$scope_; + $q = _$q_; job = _job_; ansi = new Ansi(); @@ -80,10 +90,6 @@ function JobsIndexController (_job_, JobEventModel, _$sce_, _$timeout_, _$scope_ table.html($sce.getTrustedHtml(html)); $compile(table.contents())($scope); - meta.next = job.get('related.job_events.next'); - meta.prev = job.get('related.job_events.previous'); - meta.cursor = job.get('related.job_events.results').length; - container.scroll(onScroll); }); } @@ -96,10 +102,13 @@ function next () { } }; - job.next(config) - .then(cursor => { - meta.next = job.get('related.job_events.next'); - meta.prev = job.get('related.job_events.previous'); + console.log('[2] getting next page'); + return job.next(config) + .then(events => { + console.log(events); + if (!events) { + return $q.resolve(); + } console.log(ROW_LIMIT); console.log(getRowCount()); @@ -108,15 +117,21 @@ function next () { console.log('above:', getRowsAbove()); console.log('below:', getRowsBelow()); - append(cursor); - shift(); + return shift() + .then(() => append(events)); }); } function prev () { - job.prev({ related: 'job_events' }) - .then(cursor => { - console.log(cursor); + console.log('[2] getting previous page'); + return job.prev({ related: 'job_events' }) + .then(events => { + if (!events) { + return $q.resolve(); + } + + return pop() + .then(() => prepend(events)); }); } @@ -163,29 +178,66 @@ function getRowsInView () { return Math.floor(viewHeight / rowHeight); } -function append (cursor) { - const events = job.get('related.job_events.results').slice(cursor); - const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parseEvents(events)))); - const table = $(ELEMENT_TBODY); +function append (events) { + console.log('[4] appending next page'); - table.append(rows); - $compile(rows.contents())($scope); + return $q(resolve => { + const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parseEvents(events)))); + const table = $(ELEMENT_TBODY); + + table.append(rows); + $compile(rows.contents())($scope); + + $timeout(() => { + resolve(); + }); + }); +} + +function prepend (events) { + console.log('[4] prepending next page'); + + return $q(resolve => { + const rows = $($sce.getTrustedHtml($sce.trustAsHtml(parseEvents(events)))); + const table = $(ELEMENT_TBODY); + + table.prepend(rows); + $compile(rows.contents())($scope); + + $timeout(() => { + resolve(); + }); + }); +} + +function pop () { + console.log('[3] popping old page'); + return $q(resolve => { + const count = getRowCount() - ROW_LIMIT; + const rows = $(ELEMENT_TBODY).children().slice(-count); + + rows.empty(); + rows.remove(); + + $timeout(() => { + resolve(); + }); + }); } -/* - *function prepend (cursor) { - * - *} - * - */ function shift () { - const count = getRowCount() - ROW_LIMIT; - const rows = $(ELEMENT_TBODY).children().slice(0, count); + console.log('[3] shifting old page'); + return $q(resolve => { + const count = getRowCount() - ROW_LIMIT; + const rows = $(ELEMENT_TBODY).children().slice(0, count); - console.log(count, rows); + rows.empty(); + rows.remove(); - rows.empty(); - rows.remove(); + $timeout(() => { + resolve(); + }); + }); } function expand () { @@ -419,28 +471,43 @@ function onScroll () { meta.scroll.inProgress = true; - $timeout(() => { - const top = container[0].scrollTop; - const bottom = top + SCROLL_BUFFER + container[0].offsetHeight; + const top = container[0].scrollTop; + const bottom = top + SCROLL_BUFFER + container[0].offsetHeight; - meta.scroll.inProgress = false; + if (top === 0) { + console.log('[1] scroll to top'); + vm.menu.scroll.display = false; - if (top === 0) { - vm.menu.scroll.display = false; + prev() + .then(() => { + console.log('[5] scroll reset'); + meta.scroll.inProgress = false; + }); - prev(); + return; + } - return; - } + vm.menu.scroll.display = true; - vm.menu.scroll.display = true; + if (bottom >= container[0].scrollHeight) { + console.log('[1] scroll to bottom'); - if (bottom >= container[0].scrollHeight && meta.next) { - next(); - } - }, SCROLL_LOAD_DELAY); + next() + .then(() => { + console.log('[5] scroll reset'); + meta.scroll.inProgress = false; + }); + } } -JobsIndexController.$inject = ['job', 'JobEventModel', '$sce', '$timeout', '$scope', '$compile']; +JobsIndexController.$inject = [ + 'job', + 'JobEventModel', + '$sce', + '$timeout', + '$scope', + '$compile', + '$q' +]; module.exports = JobsIndexController; diff --git a/awx/ui/client/features/output/index.js b/awx/ui/client/features/output/index.js index c3049bdfb7..1e8fc4e23e 100644 --- a/awx/ui/client/features/output/index.js +++ b/awx/ui/client/features/output/index.js @@ -35,9 +35,9 @@ function JobsRun ($stateExtender, strings) { return new Jobs('get', id) .then(job => job.extend('job_events', { pageCache: true, - pageLimit: 2, + pageLimit: 4, params: { - page_size: 1000, + page_size: 100, order_by: 'start_line' }, })); diff --git a/awx/ui/client/lib/models/Base.js b/awx/ui/client/lib/models/Base.js index 77400855ff..e9723655f4 100644 --- a/awx/ui/client/lib/models/Base.js +++ b/awx/ui/client/lib/models/Base.js @@ -110,11 +110,17 @@ function httpGet (config = {}) { this.page.current = 1; if (config.pageCache) { - this.page.cache = { - root: {} - }; - + this.page.cachedPages = this.page.cachedPages || {}; + this.page.cache = this.page.cache || {}; this.page.limit = config.pageLimit || false; + + if (!_.has(this.page.cachedPages, 'root')) { + this.page.cachedPages.root = []; + } + + if (!_.has(this.page.cache, 'root')) { + this.page.cache.root = {}; + } } } } @@ -132,7 +138,10 @@ function httpGet (config = {}) { this.model.GET = res.data; if (config.pageCache) { - this.page.cache[this.page.current] = res.data.results; + this.page.cache.root[this.page.current] = res.data.results; + this.page.cachedPages.root.push(this.page.current); + this.page.count = res.data.count; + this.page.last = Math.ceil(res.data.count / this.page.size); } return res; @@ -352,8 +361,17 @@ function extend (related, config) { this.page.current = 1; if (config.pageCache) { + this.page.cachedPages = this.page.cachedPages || {}; this.page.cache = this.page.cache || {}; this.page.limit = config.pageLimit || false; + + if (!_.has(this.page.cachedPages, `related.${related}`)) { + _.set(this.page.cachedPages, `related.${related}`, []); + } + + if (!_.has(this.page.cache, `related.${related}`)) { + _.set(this.page.cache, `related.${related}`, []); + } } } @@ -367,9 +385,10 @@ function extend (related, config) { this.set(req.method, `related.${related}`, data); if (config.pageCache) { - const key = `related.${related}.${this.page.current}`; - - _.set(this.page.cache, key, data.results); + this.page.cache.related[related][this.page.current] = data.results; + this.page.cachedPages.related[related].push(this.page.current); + this.page.count = data.count; + this.page.last = Math.ceil(data.count / this.page.size); } return this; @@ -383,16 +402,15 @@ function goToPage (config, page) { const params = config.params || {}; let url; - let count; let key; let pageNumber; + let pageCache; + let pagesInCache; if (config.related) { - count = this.get(`related.${config.related}.count`); url = `${this.endpoint}${config.related}/`; key = `related.${config.related}`; } else { - count = this.get('count'); url = this.endpoint; key = 'root'; } @@ -400,29 +418,34 @@ function goToPage (config, page) { params.page_size = this.page.size; if (page === 'next') { - // if (at max) pageNumber = this.page.current + 1; } else if (page === 'previous') { - // if (at min) pageNumber = this.page.current - 1; } else if (page === 'first') { - // if (at min) - pageNumber = 1; } else if (page === 'last') { - // if (at min) - - pageNumber = Math.floor(count / this.page.size); - } else if (typeof pageNumber === 'number') { + pageNumber = this.page.last; + } else { pageNumber = page; } - if (this.page.cache && this.page.cache[pageNumber]) { - return Promise.resolve(this.page.cache[pageNumber]); + this.page.current = pageNumber; + + if (pageNumber < 1 || pageNumber > this.page.last) { + return Promise.resolve(null); + } + + if (this.page.cache) { + pageCache = _.get(this.page.cache, key); + pagesInCache = _.get(this.page.cachedPages, key); + + if (_.has(pageCache, pageNumber)) { + return Promise.resolve(pageCache[pageNumber]); + } } params.page_size = this.page.size; - params.page = this.page.current; + params.page = pageNumber; const req = { method: 'GET', @@ -432,98 +455,28 @@ function goToPage (config, page) { return $http(req) .then(({ data }) => { - if (this.page.cache) { - _.set(this.page.cache, `${key}.${pageNumber}`, data.results); + if (pageCache) { + pageCache[pageNumber] = data.results; + pagesInCache.push(pageNumber); + + if (pagesInCache.length > this.page.limit) { + const pageToDelete = pagesInCache.shift(); + + delete pageCache[pageToDelete]; + } } - console.log('cache', this.page.cache); + return data.results; }); } function next (config = {}) { return this.goToPage(config, 'next'); -/* - * .then(({ data }) => { - * let cursor = 0; - * - * if (this.pageCache) { - * results = results || []; - * data.results = results.concat(data.results); - * cursor = results.length; - * - * if (this.pageLimit && this.pageLimit * this.pageSize < data.results.length) { - * const removeCount = data.results.length - this.pageLimit * this.pageSize; - * - * data.results.splice(0, removeCount); - * cursor -= removeCount; - * } - * } - * - * if (config.related) { - * this.set('get', `related.${config.related}`, data); - * } else { - * this.set('get', data); - * } - * - * this.page.current++; - * - * return cursor <= 0 ? 0 : cursor; - * }); - */ } function prev (config = {}) { - return this.goToPage(config, 'prev'); + return this.goToPage(config, 'previous'); } -/* - * let url; - * let results; - * - * console.log(config, config.cursor) - * if (config.related) { - * url = this.get(`related.${config.related}.next`); - * results = this.get(`related.${config.related}.results`) || []; - * } else { - * url = this.get('next'); - * results = this.get('results'); - * } - * - * if (!url) { - * return Promise.resolve(null); - * } - * - * const req = { - * method: 'GET', - * url - * }; - * - * return $http(req) - * .then(({ data }) => { - * let cursor = 0; - * - * if (this.pageCache) { - * results = results || []; - * data.results = results.concat(data.results); - * cursor = results.length; - * - * if (this.pageLimit && this.pageLimit * this.pageSize < data.results.length) { - * const removeCount = data.results.length - this.pageLimit * this.pageSize; - * - * data.results.splice(0, removeCount); - * cursor -= removeCount; - * } - * } - * - * if (config.related) { - * this.set('get', `related.${config.related}`, data); - * } else { - * this.set('get', data); - * } - * - * return cursor <= 0 ? 0 : cursor; - * }); - *} - */ function normalizePath (resource) { const version = '/api/v2/';