Repository: tez Updated Branches: refs/heads/master ec45c510c -> 9faa54c2c
TEZ-2345. Tez UI: Enable cell level loading in all DAGs table (Sreenath Somarajapuram via pramachandran) Project: http://git-wip-us.apache.org/repos/asf/tez/repo Commit: http://git-wip-us.apache.org/repos/asf/tez/commit/9faa54c2 Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/9faa54c2 Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/9faa54c2 Branch: refs/heads/master Commit: 9faa54c2c356cccbab7e2c2350bffc6fba7019bd Parents: ec45c51 Author: Prakash Ramachandran <[email protected]> Authored: Wed Apr 22 13:57:23 2015 +0530 Committer: Prakash Ramachandran <[email protected]> Committed: Wed Apr 22 13:57:23 2015 +0530 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../app/scripts/controllers/dags_controller.js | 199 +++++++++++-------- .../app/scripts/mixins/paginated_content.js | 83 +++----- .../main/webapp/app/scripts/views/dropdown.js | 35 ++++ tez-ui/src/main/webapp/app/styles/colors.less | 1 + tez-ui/src/main/webapp/app/styles/main.less | 186 +++++++++++------ tez-ui/src/main/webapp/app/styles/shared.less | 10 +- tez-ui/src/main/webapp/app/templates/dags.hbs | 79 +++++++- 8 files changed, 387 insertions(+), 207 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tez/blob/9faa54c2/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 35cf312..5c91872 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -9,6 +9,7 @@ INCOMPATIBLE CHANGES TEZ-1993. Implement a pluggable InputSizeEstimator for grouping fairly ALL CHANGES: + TEZ-2345. Tez UI: Enable cell level loading in all DAGs table TEZ-2330. Create reconfigureVertex() API for input based initialization TEZ-2292. Add e2e test for error reporting when vertex manager invokes plugin APIs http://git-wip-us.apache.org/repos/asf/tez/blob/9faa54c2/tez-ui/src/main/webapp/app/scripts/controllers/dags_controller.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/scripts/controllers/dags_controller.js b/tez-ui/src/main/webapp/app/scripts/controllers/dags_controller.js index f6a7013..94c6505 100644 --- a/tez-ui/src/main/webapp/app/scripts/controllers/dags_controller.js +++ b/tez-ui/src/main/webapp/app/scripts/controllers/dags_controller.js @@ -28,7 +28,6 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C // query parameters supported through url. The same named variables in this controller get // bound automatically to the ones defined in the route. queryParams: { - fromID: true, status_filter: 'status', user_filter: 'user', appId_filter: 'appid', @@ -38,14 +37,38 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C fromID: null, status_filter: null, - user_filter: null, - appId_filter: null, - dagName_filter: null, - fields: 'events,primaryfilters,otherinfo', + boundFilterValues: Em.Object.create({ + status: null + }), + visibleFilters: null, + + init: function () { + this._super(); + this._filterVisiblilityObserver(); + }, + + _paramObserver: function () { + this.set('boundFilterValues', Em.Object.create({ + status: this.get('status_filter'), + user: this.get('user_filter'), + appId: this.get('appId_filter'), + dagName: this.get('dagName_filter') + })); + }.observes('status_filter', 'user_filter', 'appId_filter', 'dagName_filter'), + + _filterVisiblilityObserver: function () { + var visibleFilters = Em.Object.create(); + this.get('columns').forEach(function (column) { + if(column.get('enableFilter')) { + visibleFilters.set(column.get('id'), true); + } + }); + this.set('visibleFilters', visibleFilters); + }.observes('columns'), loadData: function() { var filters = { @@ -69,7 +92,6 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C var that = this, store = this.get('store'), childEntityType = this.get('childEntityType'), - fetcher, record; var defaultErrMsg = 'Error while loading dag info.'; @@ -78,16 +100,22 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C store.unloadAll('dagProgress'); store.findQuery(childEntityType, this.getFilterProperties()).then(function(entities){ - var loaders = []; + that.set('entities', entities); + that.set('loading', false); + entities.forEach(function (dag) { var appId = dag.get('applicationId'); if(appId) { - // Pivot attempt selection logic record = store.getById('appDetail', appId); if(record && !App.Helpers.misc.isStatusInUnsuccessful(record.get('appState'))) { store.unloadRecord(record); } - fetcher = store.find('appDetail', appId).then(function (app) { + } + }); + entities.forEach(function (dag) { + var appId = dag.get('applicationId'); + if(appId) { + store.find('appDetail', appId).then(function (app) { dag.set('appDetail', app); if (dag.get('status') === 'RUNNING') { dag.set('status', App.Helpers.misc.getRealStatus( @@ -95,17 +123,15 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C app.get('appState'), app.get('finalAppStatus') )); - App.Helpers.misc.removeRecord(store, 'tezApp', 'tez_' + appId); } - return store.find('tezApp', 'tez_' + appId).then(function (app) { - dag.set('tezApp', app); - }); + }) + .catch(function(error) { + Em.Logger.error('Failed to fetch appDetail' + error); }); - loaders.push(fetcher); - //Load tezApp details + if (dag.get('status') === 'RUNNING') { App.Helpers.misc.removeRecord(store, 'dagProgress', dag.get('id')); - amInfoFetcher = store.find('dagProgress', dag.get('id'), { + store.find('dagProgress', dag.get('id'), { appId: dag.get('applicationId'), dagIdx: dag.get('idx') }) @@ -115,32 +141,29 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C .catch(function(error) { Em.Logger.error('Failed to fetch dagProgress' + error); }); - loaders.push(amInfoFetcher); } } }); - Em.RSVP.allSettled(loaders).then(function(){ - that.set('entities', entities); - that.set('loading', false); - }); }).catch(function(error){ Em.Logger.error(error); var err = App.Helpers.misc.formatError(error, defaultErrMsg); var msg = 'error code: %@, message: %@'.fmt(err.errCode, err.msg); App.Helpers.ErrorBar.getInstance().show(msg, err.details); }); - }, + }.observes('fields'), actions : { - filterUpdated: function(filterID, value) { - // any validations required goes here. - if (!!value) { - this.set(filterID, value); - } else { - this.set(filterID, null); - } + filterUpdated: function() { + Em.run.later(); + var filterValues = this.get('boundFilterValues'); + this.setProperties({ + status_filter: filterValues.get('status') || null, + user_filter: filterValues.get('user') || null, + appId_filter: filterValues.get('appId') || null, + dagName_filter: filterValues.get('dagName') || null, + }); this.loadData(); - }, + } }, /* @@ -148,19 +171,32 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C * @return Array of column configs */ defaultColumnConfigs: function () { + var store = this.get('store'); + + function onProgressChange() { + var progress = this.get('dag.progress'), + pct; + if (Ember.typeOf(progress) === 'number') { + pct = App.Helpers.number.fractionToPercentage(progress); + this.set('progress', pct); + } + } + + function onStatusChange() { + this.set('status', this.get('dag.status')); + } + return [ { id: 'dagName', headerCellName: 'Dag Name', - filterID: 'dagName_filter', - tableCellViewClass: Em.Table.TableCell.extend({ - template: Em.Handlebars.compile( - "{{#link-to 'dag.index' view.cellContent.id class='ember-table-content'}}{{view.cellContent.name}}{{/link-to}}") - }), + templateName: 'components/basic-table/linked-cell', + enableFilter: true, getCellContent: function(row) { return { - id: row.get('id'), - name: row.get('name') + linkTo: 'dag.index', + entityId: row.get('id'), + displayText: row.get('name') }; } }, @@ -172,38 +208,34 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C { id: 'user', headerCellName: 'Submitter', - filterID: 'user_filter', - contentPath: 'user' + contentPath: 'user', + enableFilter: true }, { id: 'status', headerCellName: 'Status', - filterID: 'status_filter', - filterType: 'dropdown', - dropdownValues: App.Helpers.misc.dagStatusUIOptions, - tableCellViewClass: Em.Table.TableCell.extend({ - template: Em.Handlebars.compile( - '<span class="ember-table-content"> \ - <i {{bind-attr class=":task-status view.cellContent.statusIcon"}}></i>\ - {{view.cellContent.status}}\ - {{#if view.cellContent.progress}} {{bs-badge content=view.cellContent.progress}}{{/if}}</span>') - }), + templateName: 'components/basic-table/status-cell', + enableFilter: true, getCellContent: function(row) { - var pct; - if (Ember.typeOf(row.get('progress')) === 'number') { - pct = App.Helpers.number.fractionToPercentage(row.get('progress')); + var status = row.get('status'), + content = Ember.Object.create({ + dag: row, + status: status, + statusIcon: App.Helpers.misc.getStatusClassForEntity(status) + }); + + if(status == 'RUNNING') { + row.addObserver('progress', content, onProgressChange); + row.addObserver('status', content, onStatusChange); } - var dagStatus = row.get('status'); - return { - status: dagStatus, - statusIcon: App.Helpers.misc.getStatusClassForEntity(dagStatus), - progress: pct - }; + + return content; } }, { id: 'startTime', headerCellName: 'Start Time', + contentPath: 'startTime', getCellContent: function(row) { return App.Helpers.date.dateFormat(row.get('startTime')); } @@ -219,37 +251,44 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C id: 'duration', headerCellName: 'Duration', getCellContent: function(row) { - var st = row.get('startTime'); - var et = row.get('endTime'); - if (st && et) { - return App.Helpers.date.durationSummary(st, et); - } + return App.Helpers.date.timingFormat(row.get('duration'), 1); } }, { id: 'appId', headerCellName: 'Application ID', - filterID: 'appId_filter', - tableCellViewClass: Em.Table.TableCell.extend({ - template: Em.Handlebars.compile( - "{{#if view.cellContent.enableLink}}\ - {{#link-to 'tez-app' view.cellContent.appId class='ember-table-content'}}{{view.cellContent.appId}}{{/link-to}}\ - {{else}}\ - <span class='ember-table-content'>{{view.cellContent.appId}}</span>\ - {{/if}}") - }), + templateName: 'components/basic-table/linked-cell', + enableFilter: true, getCellContent: function(row) { - return { - enableLink: row.get('tezApp') && row.get('appDetail'), - appId: row.get('applicationId') + var appId = row.get('applicationId'); + if(appId) { + return Em.RSVP.allSettled([ + store.find('appDetail', appId), + store.find('tezApp', 'tez_' + appId) + ]).then(function (response) { + var content = { + displayText: row.get('applicationId'), + entityId: row.get('applicationId') + }; + if(response.get('0.value') && response.get('1.value')) { + content.linkTo = 'tez-app'; + } + return content; + }); } } }, { id: 'queue', headerCellName: 'Queue', + templateName: 'components/basic-table/bounded-basic-cell', getCellContent: function(row) { - return row.get('appDetail.queue') || 'Not Available'; + var appId = row.get('applicationId'); + if(appId) { + return store.find('appDetail', appId).then(function (app) { + return app.get('queue'); + }); + } } } ]; @@ -266,12 +305,4 @@ App.DagsController = Em.ObjectController.extend(App.PaginatedContentMixin, App.C ); }.property(), - columns: function() { - var visibleColumnConfigs = this.get('columnConfigs').filter(function (column) { - return this.visibleColumnIds[column.id]; - }, this); - - return App.Helpers.misc.createColumnsFromConfigs(visibleColumnConfigs); - }.property('visibleColumnIds'), - }); http://git-wip-us.apache.org/repos/asf/tez/blob/9faa54c2/tez-ui/src/main/webapp/app/scripts/mixins/paginated_content.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/scripts/mixins/paginated_content.js b/tez-ui/src/main/webapp/app/scripts/mixins/paginated_content.js index 5e158e1..13e27cc 100644 --- a/tez-ui/src/main/webapp/app/scripts/mixins/paginated_content.js +++ b/tez-ui/src/main/webapp/app/scripts/mixins/paginated_content.js @@ -19,13 +19,13 @@ App.PaginatedContentMixin = Em.Mixin.create({ // paging related values. These are bound automatically to the values in url. via the queryParams // defined in the route. - count: 10, + rowCount: 10, page: 1, fromID: null, // The dropdown contents for number of items to show. - countOptions: [5, 10, 25, 50, 100], + rowCountOptions: [5, 10, 25, 50, 100], isRefreshable: true, @@ -33,14 +33,10 @@ App.PaginatedContentMixin = Em.Mixin.create({ * store the first dag id on a page so that we can navigate back and store the last one * (not shown on page to get the id where next page starts) */ - navIDs: { - prevIDs: [], - currentID: undefined, - nextID: undefined - }, + navIDs: [], queryParams: { - count: true, + rowCount: true, }, entities: [], @@ -50,7 +46,11 @@ App.PaginatedContentMixin = Em.Mixin.create({ load: function() { this.resetNavigation(); this.loadEntities(); - }.observes('count'), + }.observes('rowCount'), + + lastPage: function () { + return this.get('navIDs.length') + 1; + }.property('navIDs.length'), sortedContent: function() { // convert to a ArrayController. we do not sort at this point as the data is @@ -59,7 +59,7 @@ App.PaginatedContentMixin = Em.Mixin.create({ model: this.get('entities') }); this.updatePagination(sorted.toArray()); - return sorted.slice(0, this.count); + return sorted.slice(0, this.rowCount); }.property('entities', 'numEntities'), updateLoading: function () { @@ -104,65 +104,36 @@ App.PaginatedContentMixin = Em.Mixin.create({ }, resetNavigation: function() { - this.set('navIDs.prevIDs', []); - this.set('navIDs.currentID', ''); - this.set('navIDs.nextID', ''); + this.set('navIDs', []); this.set('fromID', null); this.set('page', 1); }, updatePagination: function(dataArray) { - if (!!dataArray && dataArray.get('length') > 0) { - this.set('navIDs.currentID', dataArray.objectAt(0).get('id')); - var nextID = undefined; - if (dataArray.get('length') > this.count) { - // save the last id, so that we can use that as firt id on next page. - nextID = dataArray.objectAt(this.count).get('id'); + var nextFromId = null, + navIDs = this.get('navIDs'), + rowCount = this.get('rowCount'); + + if(dataArray && dataArray.length == rowCount + 1) { + nextFromId = dataArray.objectAt(rowCount).get('id'); + if (navIDs.indexOf(nextFromId) == -1 && + this.get('page') >= navIDs.get('length')) { + navIDs.pushObject(nextFromId); } - this.set('navIDs.nextID', nextID); } }, - hasPrev: function() { - return this.navIDs.prevIDs.length > 0; - }.property('navIDs.prevIDs.[]', 'navIDs.prevIDs.length', 'fromID', 'page'), - - hasNext: function() { - return !!this.navIDs.nextID; - }.property('navIDs.nextID'), - actions:{ - // go to previous page - navigatePrev: function () { - var prevPageId = this.navIDs.prevIDs.popObject(); - this.set('fromID', prevPageId); - this.set('loading', true); - this.set('page', this.get('page') - 1); - this.loadEntities(); - }, - refresh: function () { this.load(); }, - // goto first page. - navigateFirst: function() { - var firstPageId = this.navIDs.prevIDs[0]; - this.set('navIDs.prevIDs', []); - this.set('fromID', firstPageId); + changePage: function (pageNum) { + this.set('fromID', this.get('navIDs.' + (pageNum - 2)) || null); this.set('loading', true); - this.set('page', 1); + this.set('page', pageNum); this.loadEntities(); - }, - - // go to next page - navigateNext: function () { - this.navIDs.prevIDs.pushObject(this.navIDs.currentID); - this.set('fromID', this.get('navIDs.nextID')); - this.set('loading', true); - this.set('page', this.get('page') + 1); - this.loadEntities(); - }, + } }, _concatFilters: function(obj) { @@ -177,7 +148,7 @@ App.PaginatedContentMixin = Em.Mixin.create({ getFilterProperties: function() { var params = { - limit: this.count + 1 + limit: this.rowCount + 1 }; var f = this._paginationFilters; @@ -213,8 +184,8 @@ App.PaginatedContentMixin = Em.Mixin.create({ params['secondaryFilter'] = secondary; } - if (!Em.empty(this.fromID)) { - params['fromId'] = this.fromID; + if (!Em.empty(this.get('fromID'))) { + params['fromId'] = this.get('fromID'); } return params; http://git-wip-us.apache.org/repos/asf/tez/blob/9faa54c2/tez-ui/src/main/webapp/app/scripts/views/dropdown.js ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/scripts/views/dropdown.js b/tez-ui/src/main/webapp/app/scripts/views/dropdown.js new file mode 100644 index 0000000..be97507 --- /dev/null +++ b/tez-ui/src/main/webapp/app/scripts/views/dropdown.js @@ -0,0 +1,35 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +App.Dropdown = Em.Select.extend({ + currentValue: null, + init: function () { + this._super(); + this.set('currentValue', this.get('value')); + }, + change: function() { + var value = this.get('value'), + target = this.get('target') || this.get('context'); + + if(target && value != this.get('currentValue')) { + Em.run.later(target.send.bind(target, this.get('action'), value), 100); + this.set('currentValue', value); + } + return true; + } +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/tez/blob/9faa54c2/tez-ui/src/main/webapp/app/styles/colors.less ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/styles/colors.less b/tez-ui/src/main/webapp/app/styles/colors.less index 9bf4b61..aa0d96a 100644 --- a/tez-ui/src/main/webapp/app/styles/colors.less +++ b/tez-ui/src/main/webapp/app/styles/colors.less @@ -32,6 +32,7 @@ @text-color: #666666; @text-red: red; +@text-light: #BBBBBB; @top-nav-bg-color-from: #d5d5d5; @top-nav-bg-color-to: #f0f0f0; http://git-wip-us.apache.org/repos/asf/tez/blob/9faa54c2/tez-ui/src/main/webapp/app/styles/main.less ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/styles/main.less b/tez-ui/src/main/webapp/app/styles/main.less index 4687ac4..8204b19 100644 --- a/tez-ui/src/main/webapp/app/styles/main.less +++ b/tez-ui/src/main/webapp/app/styles/main.less @@ -56,16 +56,6 @@ body, html { } } - .table-control { - .align-children-left { - vertical-align: top; - padding-top: 4px; - } - .align-children-right { - margin-top: -8px; - } - } - .load-component { margin-bottom: 5px; @@ -392,6 +382,9 @@ body, html { .task-status { .fa; .fa-lg; + .absolute; + + top: 7px; &.success { .fa-icon(check-circle); @@ -424,6 +417,9 @@ body, html { color: @unknown-color; } } +.status-msg { + margin-left: 20px; +} .fa-action { .fa; @@ -531,6 +527,113 @@ div.indent { color: black; } +.row-select { + margin-left: 5px; + + display: inline-block; + text-align: center; + + :first-child { + margin-bottom: -3px; + font-size: .85em; + } +} + +.dag-header { + .margin-small-horizontal; + + .align-children-left { + width: 65%; + .inline-block; + } + .align-children-right { + width: 35%; + .inline-block; + } + + margin-bottom: -5px; + margin-top: 10px; + + .pagination-view { + .page-list { + margin-bottom: 2px; + } + } + + .filter-elements { + .inline-block; + + margin-left: 5px; + display: inline-block; + + input[type=text], select { + width: 110px; + } + input, select { + height: 20px; + border-radius: 5px; + border: 1px solid @border-color; + } + + .load-counter-check { + margin-left: 10px; + vertical-align: sub; + } + + :first-child { + margin-bottom: -3px; + font-size: .85em; + + padding: 2px; + } + } +} + +.pagination-view { + .inline-block; + + .page-list { + .inline-block; + .align-top; + + overflow: hidden; + + border: 1px solid @border-color; + border-radius: 5px; + + padding: 0px; + + font-size: 0px; + + li { + .inline-block; + + padding: 6px 10px; + font-size: 14px; + + border-left: 1px solid @border-color; + + pointer-events: none; + + &.clickable { + pointer-events: auto; + &:hover { + background-color: @bg-grey; + cursor: pointer; + } + } + } + + .total-page-count { + font-size: .8em; + } + + :first-child { + border-left: none; + } + } +} + .table-container { .use-gpu; @@ -599,61 +702,7 @@ div.indent { .fa-icon(spinner); .fa-spin; .fa-fw; - } - - .pagination-view { - .inline-block; - - .page-list { - .inline-block; - .align-top; - - border: 1px solid @border-color; - border-radius: 5px; - - padding: 0px; - - font-size: 0px; - - li { - .inline-block; - - padding: 6px 10px; - font-size: 14px; - - border-left: 1px solid @border-color; - - pointer-events: none; - - &.clickable { - pointer-events: auto; - &:hover { - background-color: @bg-grey; - cursor: pointer; - } - } - } - - .total-page-count { - font-size: .8em; - } - - :first-child { - border-left: none; - } - } - - .row-select { - margin-left: 5px; - - display: inline-block; - text-align: center; - - :first-child { - margin-bottom: -3px; - font-size: .85em; - } - } + .absolute; } .table-body-container{ @@ -689,6 +738,13 @@ div.indent { text-overflow: ellipsis; white-space: nowrap; height: 18px; + + .message { + color: @text-light; + .waiting { + color: @text-color; + } + } } .sort-icon { http://git-wip-us.apache.org/repos/asf/tez/blob/9faa54c2/tez-ui/src/main/webapp/app/styles/shared.less ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/styles/shared.less b/tez-ui/src/main/webapp/app/styles/shared.less index cebd837..7cece16 100644 --- a/tez-ui/src/main/webapp/app/styles/shared.less +++ b/tez-ui/src/main/webapp/app/styles/shared.less @@ -37,6 +37,10 @@ visibility: hidden !important; } +.no-margin { + margin: 0px !important; +} + .no-pointer { pointer-events: none; } @@ -45,10 +49,14 @@ white-space: nowrap; } -.align-top{ +.align-top { vertical-align: top; } +.align-super { + vertical-align: super; +} + .inline-block { display: inline-block; } http://git-wip-us.apache.org/repos/asf/tez/blob/9faa54c2/tez-ui/src/main/webapp/app/templates/dags.hbs ---------------------------------------------------------------------- diff --git a/tez-ui/src/main/webapp/app/templates/dags.hbs b/tez-ui/src/main/webapp/app/templates/dags.hbs index d0e83c4..727e28a 100644 --- a/tez-ui/src/main/webapp/app/templates/dags.hbs +++ b/tez-ui/src/main/webapp/app/templates/dags.hbs @@ -21,5 +21,82 @@ </ul> <div class='margin-small-vertical'> - {{partial 'common/table-with-spinner'}} + {{#unless loading}} + {{load-time-component + isRefreshable=isRefreshable + time=sortedContent.0.timeStamp + refresh='refresh' + }} + <div class='dag-header'> + <div class="align-children-left"> + {{#if visibleFilters.dagName}} + <div class='filter-elements'> + <div>Dag Name</div> + {{input + action="filterUpdated" + value=boundFilterValues.dagName + placeholder="Search..." + }} + </div> + {{/if}} + {{#if visibleFilters.user}} + <div class='filter-elements'> + <div>Submitter</div> + {{input + action="filterUpdated" + value=boundFilterValues.user + placeholder="Search..." + }} + </div> + {{/if}} + {{#if visibleFilters.status}} + <div class='filter-elements'> + <div>Status</div> + {{view App.Dropdown + optionValuePath='content.id' + optionLabelPath='content.label' + classNames='inline-display' + action='filterUpdated' + content=App.Helpers.misc.dagStatusUIOptions + value=boundFilterValues.status + }} + </div> + {{/if}} + {{#if visibleFilters.appId}} + <div class='filter-elements'> + <div>Application ID</div> + {{input + action="filterUpdated" + value=boundFilterValues.appId + placeholder="Search..." + }} + </div> + {{/if}} + </div><div class="align-children-right"> + {{view App.BasicTableComponent.PaginationView + pageNum=page + totalPages=lastPage + hideLast=true + }} + <i {{bind-attr class=':fa-action :fa-cog :left-divider'}} {{action 'selectColumns'}}></i> + </div> + </div> + {{basic-table-component + columns=columns + rows=sortedContent + + rowCountBinding='rowCount' + + statusMessage=statusMessage + }} + {{#unless sortedContent.length}} + <h1 class="no-margin">No records available!</h1> + {{/unless}} + {{else}} + {{partial 'partials/loading-spinner'}} + <div class="text-align-center"> + {{statusMessage}} + </div> + {{/unless}} + </div>
