You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tez.apache.org by pr...@apache.org on 2015/04/07 21:38:00 UTC
tez git commit: TEZ-2236. Tez UI: Support loading of all tasks in the
dag tasks page (Sreenath Somarajapuram via pramachandran)
Repository: tez
Updated Branches:
refs/heads/master 62a348cea -> 9316fe627
TEZ-2236. Tez UI: Support loading of all tasks in the dag tasks page (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/9316fe62
Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/9316fe62
Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/9316fe62
Branch: refs/heads/master
Commit: 9316fe627a9153a5caf8c653e97300c7b4bb8095
Parents: 62a348c
Author: Prakash Ramachandran <pr...@hortonworks.com>
Authored: Wed Apr 8 01:06:50 2015 +0530
Committer: Prakash Ramachandran <pr...@hortonworks.com>
Committed: Wed Apr 8 01:06:50 2015 +0530
----------------------------------------------------------------------
CHANGES.txt | 1 +
tez-ui/src/main/webapp/app/scripts/app.js | 5 +-
.../basic-table/basic-table-component.js | 91 ++++
.../scripts/components/basic-table/cell-view.js | 43 ++
.../components/basic-table/column-definition.js | 46 ++
.../components/basic-table/header-cell-view.js | 52 +++
.../components/basic-table/pagination-view.js | 62 +++
.../webapp/app/scripts/controllers/dag_tasks.js | 247 ++++-------
.../controllers/table-page-controller.js | 39 ++
.../app/scripts/helpers/handlebarHelpers.js | 8 +
.../src/main/webapp/app/scripts/helpers/misc.js | 60 ++-
.../webapp/app/scripts/helpers/misc.js.orig | 436 +++++++++++++++++++
.../scripts/mixins/data-array-loader-minxin.js | 117 +++++
.../src/main/webapp/app/scripts/models/dag.js | 4 +
tez-ui/src/main/webapp/app/scripts/router.js | 15 +-
.../scripts/views/extra-table-buttons-view.js | 23 +
tez-ui/src/main/webapp/app/styles/colors.less | 7 +-
tez-ui/src/main/webapp/app/styles/main.less | 225 +++++++++-
tez-ui/src/main/webapp/app/styles/shared.less | 24 +
.../main/webapp/app/templates/common/table.hbs | 47 ++
.../app/templates/components/basic-table.hbs | 58 +++
.../components/basic-table/basic-cell.hbs | 19 +
.../components/basic-table/header-cell.hbs | 24 +
.../components/basic-table/linked-cell.hbs | 25 ++
.../components/basic-table/logs-cell.hbs | 35 ++
.../components/basic-table/pagination-view.hbs | 38 ++
.../components/basic-table/status-cell.hbs | 29 ++
.../basic-table/task-actions-cell.hbs | 26 ++
.../app/templates/views/extra-table-buttons.hbs | 19 +
29 files changed, 1641 insertions(+), 184 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 0eb02a7..f7295f2 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-2236. Tez UI: Support loading of all tasks in the dag tasks page
TEZ-2159. Tez UI: download timeline data for offline use.
TEZ-2269. DAGAppMaster becomes unresponsive (post TEZ-2149).
TEZ-2243. documentation should explicitly specify protobuf 2.5.0.
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/app.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/app.js b/tez-ui/src/main/webapp/app/scripts/app.js
index 1a2af0e..1d8036d 100644
--- a/tez-ui/src/main/webapp/app/scripts/app.js
+++ b/tez-ui/src/main/webapp/app/scripts/app.js
@@ -183,8 +183,9 @@ require('scripts/router');
require('scripts/views/**/*');
require('scripts/models/**/*');
+require('scripts/controllers/table-page-controller');
require('scripts/controllers/**/*');
-require('scripts/components/*');
-require('scripts/components/dag-view/*');
+require('scripts/components/basic-table/basic-table-component');
+require('scripts/components/**/*');
require('scripts/adapters/*');
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/components/basic-table/basic-table-component.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/components/basic-table/basic-table-component.js b/tez-ui/src/main/webapp/app/scripts/components/basic-table/basic-table-component.js
new file mode 100644
index 0000000..5a47c78
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/components/basic-table/basic-table-component.js
@@ -0,0 +1,91 @@
+/**
+ * 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.BasicTableComponent = Em.Component.extend({
+ layoutName: 'components/basic-table',
+
+ statusMessage: null,
+ internalStatusMessage: null,
+
+ pageNum: 1,
+ rowCount: 10,
+ rowCountOptions: [5, 10, 25, 50, 100],
+ pageNavOnFooterAt: 25,
+
+ totalPages: function () {
+ return Math.ceil(this.get('rows.length') / this.get('rowCount'));
+ }.property('rows.length', 'rowCount'),
+
+ hasPageNavOnFooter: function () {
+ return this.get('enablePagination') && this.get('_rows.length') >= this.get('pageNavOnFooterAt');
+ }.property('enablePagination', '_rows.length', 'pageNavOnFooterAt'),
+
+ _showHeader: function () {
+ return this.get('enablePagination') ||
+ this.get('extraHeaderItem') ||
+ this.get('_statusMessage');
+ }.property('enablePagination', 'extraHeaderItem', '_statusMessage'),
+
+ _statusMessage: function() {
+ return this.get('internalStatusMessage') || this.get('statusMessage');
+ }.property('internalStatusMessage', 'statusMessage'),
+
+ _pageNumResetObserver: function () {
+ this.set('pageNum', 1);
+ }.observes('rowCount'),
+
+ _columns: function () {
+ var columns = this.get('columns'),
+ widthPercentageToFit = 100 / columns.length;
+
+ columns.map(function (column) {
+ var templateName = column.get('templateName'),
+ cellOptions = {
+ column: column
+ };
+
+ if(templateName) {
+ cellOptions.templateName = templateName;
+ }
+
+ column.setProperties({
+ width: widthPercentageToFit + "%",
+ cellView: App.BasicTableComponent.CellView.extend(cellOptions),
+ headerCellView: App.BasicTableComponent.HeaderCellView.extend({
+ column: column,
+ table: this
+ })
+ });
+ });
+
+ return columns;
+ }.property('columns'),
+
+ _rows: function () {
+ var startIndex = (this.get('pageNum') - 1) * this.get('rowCount');
+ return this.get('rows').slice(startIndex, startIndex + this.get('rowCount'));
+ }.property('rows.@each', 'rowCount', 'pageNum'),
+
+ actions: {
+ changePage: function (pageNum) {
+ this.set('pageNum', pageNum);
+ }
+ }
+});
+
+Em.Handlebars.helper('basic-table-component', App.BasicTableComponent);
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/components/basic-table/cell-view.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/components/basic-table/cell-view.js b/tez-ui/src/main/webapp/app/scripts/components/basic-table/cell-view.js
new file mode 100644
index 0000000..4d50cf1
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/components/basic-table/cell-view.js
@@ -0,0 +1,43 @@
+/**
+ * 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.
+ */
+
+var ObjectPromiseController = Ember.ObjectController.extend(Ember.PromiseProxyMixin),
+ naCellContent = {
+ toString: function (){
+ return 'Not available!';
+ },
+ _notAvailable: true
+ };
+
+App.BasicTableComponent.CellView = Ember.View.extend({
+ templateName: 'components/basic-table/basic-cell',
+
+ classNames: ['cell-content'],
+
+ cellContent: function () {
+ var cellContent = this.get('column').getCellContent(this.get('row'));
+
+ if(cellContent && $.isFunction(cellContent.then)) {
+ cellContent = ObjectPromiseController.create({
+ promise: cellContent
+ });
+ }
+
+ return cellContent || naCellContent;
+ }.property('row', 'column')
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/components/basic-table/column-definition.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/components/basic-table/column-definition.js b/tez-ui/src/main/webapp/app/scripts/components/basic-table/column-definition.js
new file mode 100644
index 0000000..fa0a47d
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/components/basic-table/column-definition.js
@@ -0,0 +1,46 @@
+/**
+ * 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.BasicTableComponent.ColumnDefinition = (function () {
+ function getContentAtPath(row) {
+ var contentPath = this.get('contentPath');
+
+ if(contentPath) {
+ return row.get(contentPath);
+ }
+ else {
+ throw new Error("contentPath not set!");
+ }
+ }
+
+ return Em.Object.extend({
+ contentPath: null,
+ headerCellName: "Not Available!",
+
+ width: "",
+
+ customStyle: function () {
+ return 'width:%@'.fmt(this.get('width'));
+ }.property('width'),
+
+ getSearchValue: getContentAtPath,
+ getSortValue: getContentAtPath,
+ getCellContent: getContentAtPath
+ });
+})();
+
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/components/basic-table/header-cell-view.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/components/basic-table/header-cell-view.js b/tez-ui/src/main/webapp/app/scripts/components/basic-table/header-cell-view.js
new file mode 100644
index 0000000..d6773d6
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/components/basic-table/header-cell-view.js
@@ -0,0 +1,52 @@
+/**
+ * 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.BasicTableComponent.HeaderCellView = Ember.View.extend({
+ templateName: 'components/basic-table/header-cell',
+
+ _onColResize: function (event) {
+ var data = event.data;
+
+ if(!data.startEvent) {
+ data.startEvent = event;
+ }
+
+ data.thisHeader.set(
+ 'column.width',
+ (data.startWidth + event.clientX - data.startEvent.clientX) + 'px'
+ );
+ },
+
+ _endColResize: function (event) {
+ var thisHeader = event.data.thisHeader;
+ $(document).off('mousemove', thisHeader._onColResize);
+ $(document).off('mouseup', thisHeader._endColResize);
+ },
+
+ actions: {
+ startColResize: function () {
+ var mouseTracker = {
+ thisHeader: this,
+ startWidth: $(this.get('element')).width(),
+ startEvent: null
+ };
+ $(document).on('mousemove', mouseTracker, this._onColResize);
+ $(document).on('mouseup', mouseTracker, this._endColResize);
+ }
+ }
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/components/basic-table/pagination-view.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/components/basic-table/pagination-view.js b/tez-ui/src/main/webapp/app/scripts/components/basic-table/pagination-view.js
new file mode 100644
index 0000000..4f136b1
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/components/basic-table/pagination-view.js
@@ -0,0 +1,62 @@
+/**
+ * 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.BasicTableComponent.PaginationView = Ember.View.extend({
+ templateName: 'components/basic-table/pagination-view',
+
+ classNames: ['pagination-view'],
+
+ atFirst: function () {
+ return this.get('pageNum') == 1;
+ }.property('pageNum'),
+
+ atLast: function () {
+ return this.get('pageNum') == this.get('totalPages');
+ }.property('pageNum', 'totalPages'),
+
+ _possiblePages: function () {
+ var pageNum = this.get('pageNum'),
+ totalPages = this.get('totalPages'),
+ possiblePages = [],
+ startPage = 1,
+ endPage = totalPages,
+ delta = 0;
+
+ if(totalPages > 5) {
+ startPage = pageNum - 2, endPage = pageNum + 2;
+
+ if(startPage < 1) {
+ delta = 1 - startPage;
+ }
+ else if(endPage > totalPages) {
+ delta = totalPages - endPage;
+ }
+
+ startPage += delta, endPage += delta;
+ }
+
+ while(startPage <= endPage) {
+ possiblePages.push({
+ isCurrent: startPage == pageNum,
+ pageNum: startPage++
+ });
+ }
+
+ return possiblePages;
+ }.property('pageNum', 'totalPages'),
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/controllers/dag_tasks.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/controllers/dag_tasks.js b/tez-ui/src/main/webapp/app/scripts/controllers/dag_tasks.js
index 519f06d..267eac5 100644
--- a/tez-ui/src/main/webapp/app/scripts/controllers/dag_tasks.js
+++ b/tez-ui/src/main/webapp/app/scripts/controllers/dag_tasks.js
@@ -16,185 +16,133 @@
* limitations under the License.
*/
-App.DagTasksController = Em.ObjectController.extend(App.PaginatedContentMixin, App.ColumnSelectorMixin, {
- needs: "dag",
+App.DagTasksController = App.TablePageController.extend({
controllerName: 'DagTasksController',
+ needs: "dag",
- // required by the PaginatedContentMixin
- childEntityType: 'task',
+ entityType: 'task',
+ filterEntityType: 'dag',
+ filterEntityId: Ember.computed.alias('controllers.dag.id'),
- queryParams: {
- status_filter: 'status',
- vertex_name_filter: 'vertex_name',
+ beforeLoad: function () {
+ var dagController = this.get('controllers.dag'),
+ model = dagController.get('model');
+ return model.reload().then(function () {
+ return dagController.loadAdditional(model);
+ });
},
- status_filter: null,
- vertex_name_filter: null,
- loadData: function() {
- var primaryFilter = {
- TEZ_DAG_ID : this.get('controllers.dag.id')
- };
- if (!!this.vertex_name_filter) {
- var vertexIdMap = this.get('controllers.dag.vertexIdToNameMap');
- var vertexId = App.Helpers.misc.getVertexIdFromName(vertexIdMap, this.vertex_name_filter)
- || 'unknown';
- primaryFilter = { TEZ_VERTEX_ID : vertexId };
- }
+ afterLoad: function () {
+ var data = this.get('data'),
+ isUnsuccessfulDag = App.Helpers.misc.isStatusInUnsuccessful(
+ this.get('controllers.dag.status')
+ );
+
+ data.forEach(function (task) {
+ var taskStatus = App.Helpers.misc.getFixedupDisplayStatus(task.get('status'));
- var filters = {
- primary: primaryFilter,
- secondary: {
- status: this.status_filter
+ if (taskStatus == 'RUNNING' && isUnsuccessfulDag) {
+ taskStatus = 'KILLED'
}
- }
- this.setFiltersAndLoadEntities(filters);
+ if (taskStatus != task.get('status')) {
+ task.set('status', taskStatus);
+ }
+ });
+
+ return this._super();
},
- load: function () {
- var dag = this.get('controllers.dag.model'),
- controller = this.get('controllers.dag'),
- t = this;
- t.set('loading', true);
- dag.reload().then(function () {
- return controller.loadAdditional(dag);
- }).then(function () {
- t.resetNavigation();
- t.loadEntities();
- }).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('count'),
+ columns: function() {
+ var visibleColumnConfigs = this.get('columnConfigs').filter(function (column) {
+ return this.visibleColumnIds[column.id];
+ }, this);
+
+ return App.Helpers.misc.createColumnDescription(visibleColumnConfigs);
+ }.property('visibleColumnIds'),
- loadEntities: function() {
+ defaultColumnConfigs: function() {
var that = this,
- store = this.get('store'),
- fetcher;
- childEntityType = this.get('childEntityType');
- var defaultErrMsg = 'Error while loading tasks.';
+ vertexIdToNameMap = this.get('controllers.dag.vertexIdToNameMap') || {};
- that.set('loading', true);
- store.unloadAll(childEntityType);
- store.findQuery(childEntityType, this.getFilterProperties())
- .then(function(entities){
+ function getLogContent(attempt) {
+ var yarnAppState = that.get('controllers.dag.yarnAppState'),
+ suffix,
+ link,
+ cellContent = {};
- var pivotLoaders = [];
- var dagStatus = that.get('controllers.dag.status');
- entities.forEach(function (task) {
- var taskStatus = App.Helpers.misc
- .getFixedupDisplayStatus(task.get('status'));
- if (taskStatus == 'RUNNING' &&
- App.Helpers.misc.isStatusInUnsuccessful(dagStatus)) {
- taskStatus = 'KILLED'
- }
- if (taskStatus != task.get('status')) {
- task.set('status', taskStatus);
+ if(attempt) {
+ suffix = "/syslog_" + attempt.get('id'),
+ link = attempt.get('inProgressLog') || attempt.get('completedLog');
+
+ if(link) {
+ cellContent.viewUrl = link + suffix;
}
- var taskAttemptId = task.get('successfulAttemptId') ||
- task.get('attempts.lastObject');
- if (!!taskAttemptId) {
- // Pivot attempt selection logic
- App.Helpers.misc.removeRecord(store, 'taskAttempt', taskAttemptId);
- fetcher = store.find('taskAttempt', taskAttemptId);
- fetcher.then(function (attempt) {
- task.set('pivotAttempt', attempt);
- });
- pivotLoaders.push(fetcher);
+ link = attempt.get('completedLog');
+ if (link && yarnAppState === 'FINISHED' || yarnAppState === 'KILLED' || yarnAppState === 'FAILED') {
+ cellContent.downloadUrl = link + suffix;
}
- });
- Em.RSVP.allSettled(pivotLoaders).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, error.details);
- });
- },
-
- actions : {
- filterUpdated: function(filterID, value) {
- // any validations required goes here.
- if (!!value) {
- this.set(filterID, value);
- } else {
- this.set(filterID, null);
}
- this.loadData();
+
+ cellContent.notAvailable = cellContent.viewUrl || cellContent.downloadUrl;
+
+ return cellContent;
}
- },
- defaultColumnConfigs: function() {
- var that = this,
- vertexIdToNameMap = this.get('controllers.dag.vertexIdToNameMap') || {};
return [
{
id: 'id',
headerCellName: 'Task Index',
- tableCellViewClass: Em.Table.TableCell.extend({
- template: Em.Handlebars.compile(
- "{{#link-to 'task' view.cellContent.id class='ember-table-content'}}{{view.cellContent.displayId}}{{/link-to}}")
- }),
+ templateName: 'components/basic-table/linked-cell',
+ contentPath: 'id',
getCellContent: function (row) {
var id = row.get('id'),
idPrefix = 'task_%@_'.fmt(row.get('dagID').substr(4));
return {
- id: id,
- displayId: id.indexOf(idPrefix) == 0 ? id.substr(idPrefix.length) : id
+ linkTo: 'task',
+ entityId: id,
+ displayText: id.indexOf(idPrefix) == 0 ? id.substr(idPrefix.length) : id
};
- }
+ },
},
{
id: 'vertexName',
headerCellName: 'Vertex Name',
- filterID: 'vertex_name_filter',
+ contentPath: 'vertexID',
getCellContent: function(row) {
var vertexId = row.get('vertexID');
return vertexIdToNameMap[vertexId] || vertexId;
- }
+ },
},
{
id: 'startTime',
headerCellName: 'Start Time',
+ contentPath: 'startTime',
getCellContent: function(row) {
return App.Helpers.date.dateFormat(row.get('startTime'));
- }
+ },
},
{
id: 'endTime',
headerCellName: 'End Time',
+ contentPath: 'endTime',
getCellContent: function(row) {
return App.Helpers.date.dateFormat(row.get('endTime'));
- }
+ },
},
{
id: 'duration',
headerCellName: 'Duration',
+ contentPath: '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: 'status',
headerCellName: 'Status',
- filterID: 'status_filter',
- filterType: 'dropdown',
- dropdownValues: App.Helpers.misc.taskStatusUIOptions,
- 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}}</span>')
- }),
+ templateName: 'components/basic-table/status-cell',
+ contentPath: 'status',
getCellContent: function(row) {
var status = row.get('status');
return {
@@ -206,59 +154,20 @@ App.DagTasksController = Em.ObjectController.extend(App.PaginatedContentMixin, A
{
id: 'actions',
headerCellName: 'Actions',
- tableCellViewClass: Em.Table.TableCell.extend({
- template: Em.Handlebars.compile(
- '<span class="ember-table-content">\
- {{#link-to "task.counters" view.cellContent}}counters{{/link-to}} \
- {{#link-to "task.attempts" view.cellContent}}attempts{{/link-to}}\
- </span>'
- )
- }),
- contentPath: 'id'
+ templateName: 'components/basic-table/task-actions-cell',
+ contentPath: 'id',
},
{
id: 'logs',
- textAlign: 'text-align-left',
headerCellName: 'Logs',
- tableCellViewClass: Em.Table.TableCell.extend({
- template: Em.Handlebars.compile(
- '<span class="ember-table-content">\
- {{#unless view.cellContent.notAvailable}}\
- Not Available\
- {{else}}\
- {{#if view.cellContent.viewUrl}}\
- <a target="_blank" href="//{{unbound view.cellContent.viewUrl}}">View</a>\
- \
- {{/if}}\
- {{#if view.cellContent.downloadUrl}}\
- <a target="_blank" href="{{unbound view.cellContent.downloadUrl}}?start=0" download type="application/octet-stream">Download</a>\
- {{/if}}\
- {{/unless}}\
- </span>')
- }),
+ templateName: 'components/basic-table/logs-cell',
getCellContent: function(row) {
- var yarnAppState = that.get('controllers.dag.yarnAppState'),
- attempt = row.get('pivotAttempt'),
- suffix,
- link,
- cellContent = {};
-
- if(attempt) {
- suffix = "/syslog_" + attempt.get('id'),
- link = attempt.get('inProgressLog') || attempt.get('completedLog');
+ var taskAttemptId = row.get('successfulAttemptId') || row.get('attempts.lastObject'),
+ store = that.get('store');
- if(link) {
- cellContent.viewUrl = link + suffix;
- }
- link = attempt.get('completedLog');
- if (link && yarnAppState === 'FINISHED' || yarnAppState === 'KILLED' || yarnAppState === 'FAILED') {
- cellContent.downloadUrl = link + suffix;
- }
+ if (taskAttemptId) {
+ return store.find('taskAttempt', taskAttemptId).then(getLogContent);
}
-
- cellContent.notAvailable = cellContent.viewUrl || cellContent.downloadUrl;
-
- return cellContent;
}
}
];
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js b/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js
new file mode 100644
index 0000000..002c6b5
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/controllers/table-page-controller.js
@@ -0,0 +1,39 @@
+/**
+ * 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.TablePageController = Em.ObjectController.extend(
+ App.DataArrayLoaderMixin,
+ App.ColumnSelectorMixin, {
+ queryParams: ['pageNum', 'rowCount'],
+
+ pageNum: 1,
+ rowCount: 25,
+
+ isRefreshable: true,
+
+ statusMessage: function () {
+ return this.get('loading') ? "Loading all records..." : null;
+ }.property('loading'),
+
+ actions: {
+ refresh: function () {
+ this.loadData(true);
+ }
+ }
+ }
+);
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/helpers/handlebarHelpers.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/helpers/handlebarHelpers.js b/tez-ui/src/main/webapp/app/scripts/helpers/handlebarHelpers.js
index 0cd6b9d..5fe475f 100644
--- a/tez-ui/src/main/webapp/app/scripts/helpers/handlebarHelpers.js
+++ b/tez-ui/src/main/webapp/app/scripts/helpers/handlebarHelpers.js
@@ -72,3 +72,11 @@ Em.Handlebars.helper('formatDiagnostics', function(diagnostics) {
x = replaceAll(x, ']', '</div>');
return new Handlebars.SafeString(x);
});
+
+/**
+ * Returns first-item class if called from inside a loop/each.
+ * @param view Will be _view in hbs
+ */
+Em.Handlebars.helper('firstItemCSS', function(view) {
+ return view && view.contentIndex == 0 ? 'first-item' : '';
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/helpers/misc.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/helpers/misc.js b/tez-ui/src/main/webapp/app/scripts/helpers/misc.js
index fdd69bd..27275dd 100644
--- a/tez-ui/src/main/webapp/app/scripts/helpers/misc.js
+++ b/tez-ui/src/main/webapp/app/scripts/helpers/misc.js
@@ -115,7 +115,10 @@ App.Helpers.misc = {
configuration.headerCellName = configuration.counterName || configuration.counterId;
configuration.id = '%@/%@'.fmt(configuration.counterGroupName || configuration.groupId,
configuration.counterName || configuration.counterId),
- configuration.getCellContent = App.Helpers.misc.getCounterCellContent;
+
+ configuration.getSortValue = App.Helpers.misc.getCounterCellContent;
+ configuration.getCellContent =
+ configuration.getSearchValue = App.Helpers.misc.getCounterCellContentFormatted;
return configuration;
});
},
@@ -138,6 +141,12 @@ App.Helpers.misc = {
});
},
+ createColumnDescription: function (columnConfigs) {
+ return columnConfigs.map(function (column) {
+ return App.BasicTableComponent.ColumnDefinition.create(column);
+ });
+ },
+
/*
* Returns a counter value from for a row
* @param row
@@ -145,19 +154,26 @@ App.Helpers.misc = {
*/
getCounterCellContent: function (row) {
var contentPath = this.id.split('/'),
- group = contentPath[0],
- counter = contentPath[1],
- id = row.get('id'),
- value = 'Not Available';
+ value = null;
try{
value = row.get('counterGroups').
- findBy('id', '%@/%@'.fmt(id, group)).
- get('counters').
- findBy('id', '%@/%@/%@'.fmt(id, group, counter)).
- get('value');
+ findBy('counterGroupName', contentPath[0])
+ ['counters'].
+ findBy('counterName', contentPath[1])
+ ['counterValue'];
}catch(e){}
+ return value;
+ },
+
+ /*
+ * Returns a counter value from for a row
+ * @param row
+ * @return value
+ */
+ getCounterCellContentFormatted: function (row) {
+ var value = App.Helpers.misc.getCounterCellContent.call(this, row);
return App.Helpers.number.formatNumThousands(value);
},
@@ -393,6 +409,32 @@ App.Helpers.misc = {
}
},
+ timelinePathForType: (function () {
+ var typeToPathMap = {
+ dag: 'TEZ_DAG_ID',
+ vertex: 'TEZ_VERTEX_ID',
+ task: 'TEZ_TASK_ID',
+ taskAttempt: 'TEZ_TASK_ATTEMPT_ID',
+ tezApp: 'TEZ_APPLICATION'
+ };
+ return function (type) {
+ return typeToPathMap[type];
+ };
+ })(),
+
+ getTimelineFilterForType: (function () {
+ var typeToPathMap = {
+ dag: 'TEZ_DAG_ID',
+ vertex: 'TEZ_VERTEX_ID',
+ task: 'TEZ_TASK_ID',
+ taskAttempt: 'TEZ_TASK_ATTEMPT_ID',
+ tezApp: 'applicationId'
+ };
+ return function (type) {
+ return typeToPathMap[type];
+ };
+ })(),
+
dagStatusUIOptions: [
{ label: 'All', id: null },
{ label: 'Submitted', id: 'SUBMITTED' },
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/helpers/misc.js.orig
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/helpers/misc.js.orig b/tez-ui/src/main/webapp/app/scripts/helpers/misc.js.orig
new file mode 100644
index 0000000..fdd69bd
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/helpers/misc.js.orig
@@ -0,0 +1,436 @@
+/**
+ * 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.Helpers.misc = {
+ getStatusClassForEntity: function(status, hasFailedTasks) {
+ if(!status) return '';
+
+ switch(status) {
+ case 'FAILED':
+ return 'failed';
+ case 'KILLED':
+ return 'killed';
+ case 'RUNNING':
+ return 'running';
+ case 'ERROR':
+ return 'error';
+ case 'SUCCEEDED':
+ if (!!hasFailedTasks) {
+ return 'warning';
+ }
+ /*
+ TODO: TEZ-2113
+ var counterGroups = dag.get('counterGroups');
+ var numFailedTasks = this.getCounterValueForDag(counterGroups,
+ dag.get('id'), 'org.apache.tez.common.counters.DAGCounter',
+ 'NUM_FAILED_TASKS'
+ );
+
+ if (numFailedTasks > 0) {
+ return 'warning';
+ }*/
+
+ return 'success';
+ case 'UNDEFINED':
+ return 'unknown';
+ default:
+ return 'submitted';
+ }
+ },
+
+ getRealStatus: function(entityState, yarnAppState, yarnAppFinalState) {
+ if (entityState != 'RUNNING' || (yarnAppState != 'FINISHED' && yarnAppState != 'KILLED' && yarnAppState != 'FAILED')) {
+ return entityState;
+ }
+
+ if (yarnAppState == 'KILLED' || yarnAppState == 'FAILED') {
+ return yarnAppState;
+ }
+
+ return yarnAppFinalState;
+ },
+
+ getCounterValueForDag: function(counterGroups, dagID, counterGroupName, counterName) {
+ if (!counterGroups) {
+ return 0;
+ }
+
+ var cgName = dagID + '/' + counterGroupName;
+ var cg = counterGroups.findBy('id', cgName);
+ if (!cg) {
+ return 0;
+ }
+ var counters = cg.get('counters');
+ if (!counters) {
+ return 0;
+ }
+
+ var counter = counters.findBy('id', cgName + '/' + counterName);
+ if (!counter) return 0;
+
+ return counter.get('value');
+ },
+
+ isValidDagStatus: function(status) {
+ return $.inArray(status, ['SUBMITTED', 'INITING', 'RUNNING', 'SUCCEEDED',
+ 'KILLED', 'FAILED', 'ERROR']) != -1;
+ },
+
+ isValidTaskStatus: function(status) {
+ return $.inArray(status, ['RUNNING', 'SUCCEEDED', 'FAILED', 'KILLED']) != -1;
+ },
+
+ isStatusInUnsuccessful: function(status) {
+ return $.inArray(status, ['FAILED', 'KILLED', 'UNDEFINED']) != -1;
+ },
+
+ /**
+ * To trim a complete class path with namespace to the class name.
+ */
+ getClassName: function (classPath) {
+ return classPath.substr(classPath.lastIndexOf('.') + 1);
+ },
+
+ /*
+ * Normalizes counter style configurations
+ * @param counterConfigs Array
+ * @return Normalized configurations
+ */
+ normalizeCounterConfigs: function (counterConfigs) {
+ return counterConfigs.map(function (configuration) {
+ configuration.headerCellName = configuration.counterName || configuration.counterId;
+ configuration.id = '%@/%@'.fmt(configuration.counterGroupName || configuration.groupId,
+ configuration.counterName || configuration.counterId),
+ configuration.getCellContent = App.Helpers.misc.getCounterCellContent;
+ return configuration;
+ });
+ },
+
+ /*
+ * Creates column definitions form configuration object array
+ * @param columnConfigs Array
+ * @return columnDefinitions Array
+ */
+ createColumnsFromConfigs: function (columnConfigs) {
+ return columnConfigs.map(function (columnConfig) {
+ if(columnConfig.getCellContentHelper) {
+ columnConfig.getCellContent = App.Helpers.get(columnConfig.getCellContentHelper);
+ }
+ columnConfig.minWidth = columnConfig.minWidth || 135;
+
+ return columnConfig.filterID ?
+ App.ExTable.ColumnDefinition.createWithMixins(App.ExTable.FilterColumnMixin, columnConfig) :
+ App.ExTable.ColumnDefinition.create(columnConfig);
+ });
+ },
+
+ /*
+ * Returns a counter value from for a row
+ * @param row
+ * @return value
+ */
+ getCounterCellContent: function (row) {
+ var contentPath = this.id.split('/'),
+ group = contentPath[0],
+ counter = contentPath[1],
+ id = row.get('id'),
+ value = 'Not Available';
+
+ try{
+ value = row.get('counterGroups').
+ findBy('id', '%@/%@'.fmt(id, group)).
+ get('counters').
+ findBy('id', '%@/%@/%@'.fmt(id, group, counter)).
+ get('value');
+ }catch(e){}
+
+ return App.Helpers.number.formatNumThousands(value);
+ },
+
+ /*
+ * returns a formatted message, the real cause is unknown and the error object details
+ * depends on the error cause. the function tries to handle ajax error or a native errors
+ */
+ formatError: function(error, defaultErrorMessage) {
+ var msg;
+ // for cross domain requests, the error is not set if no access control headers were found.
+ // this could be either because there was a n/w error or the cors headers being not set.
+ if (error.status === 0 && error.statusText === 'error') {
+ msg = defaultErrorMessage ;
+ } else {
+ msg = error.statusText || error.message;
+ }
+ msg = msg || 'Unknown error';
+ if (!!error.responseText) {
+ msg += error.responseText;
+ }
+
+ if(error.requestOptions) {
+ msg = '%@<br/>Could not retrieve expected data from %@ @ %@'.fmt(
+ msg,
+ error.requestOptions.targetServer,
+ error.requestOptions.url
+ )
+ }
+
+ return {
+ errCode: error.status || 'Unknown',
+ msg: msg,
+ details: error.stack
+ };
+ },
+
+ /**
+ * Normalize path
+ * @param path {String}
+ * @return normalized path {String}
+ */
+ normalizePath: function (path) {
+ if(path && path.charAt(path.length - 1) == '/') {
+ path = path.slice(0, -1);
+ }
+ return path;
+ },
+
+ // Tez originally shows the status for task and task attempt only on
+ // completion. this causes confusion to the user as the status would not be
+ // displayed. so if status is not set return the status as 'RUNNING'. We do
+ // not diffentiate between running and scheduled.
+ getFixedupDisplayStatus: function(originalStatus) {
+ // if status is not set show it as running, since originally the task did
+ // not have a status set on scheduled/running.
+ // with the new version we set the status of task as scheduled and that of
+ // task attempt as running
+ if (!originalStatus || originalStatus == 'SCHEDULED') {
+ originalStatus = 'RUNNING';
+ }
+ return originalStatus;
+ },
+
+ /**
+ * Merge content of obj2 into obj2, array elements will be concated.
+ * @param obj1 {Object}
+ * @param obj2 {Object}
+ */
+ merge: function objectMerge(obj1, obj2) {
+ $.each(obj2, function (key, val) {
+ if(Array.isArray(obj1[key]) && Array.isArray(val)) {
+ $.merge(obj1[key], val);
+ }
+ else if($.isPlainObject(obj1[key]) && $.isPlainObject(val)) {
+ objectMerge(obj1[key], val);
+ }
+ else {
+ obj1[key] = val;
+ }
+ });
+ },
+
+ getTaskIndex: function(dagID, taskID) {
+ var idPrefix = 'task_%@_'.fmt(dagID.substr(4));
+ return taskID.indexOf(idPrefix) == 0 ? taskID.substr(idPrefix.length) : id;
+ },
+
+ getVertexIdFromName: function(idToNameMap, vertexName) {
+ idToNameMap = idToNameMap || {};
+ var vertexId = undefined;
+ $.each(idToNameMap, function(id, name) {
+ if (name === vertexName) {
+ vertexId = id;
+ return false;
+ }
+ });
+ return vertexId;
+ },
+
+ /**
+ * Remove the specific record from store
+ * @param store {DS.Store}
+ * @param type {String}
+ * @param id {String}
+ */
+ removeRecord: function (store, type, id) {
+ var record = store.getById(type, id);
+ if(record) {
+ store.unloadRecord(record);
+ }
+ },
+
+ downloadDAG: function(dagID, options) {
+ var opts = options || {},
+ batchSize = opts.batchSize || 1000,
+ baseurl = '%@/%@'.fmt(App.env.timelineBaseUrl, App.Configs.restNamespace.timeline),
+ itemsToDownload = [
+ {
+ url: getUrl('TEZ_DAG_ID', dagID),
+ context: { name: 'dag', type: 'TEZ_DAG_ID' },
+ onItemFetched: processSingleItem
+ },
+ {
+ url: getUrl('TEZ_VERTEX_ID', dagID),
+ context: { name: 'vertices', type: 'TEZ_VERTEX_ID', part: 0 },
+ onItemFetched: processMultipleItems
+ },
+ {
+ url: getUrl('TEZ_TASK_ID', dagID),
+ context: { name: 'tasks', type: 'TEZ_TASK_ID', part: 0 },
+ onItemFetched: processMultipleItems
+ },
+ {
+ url: getUrl('TEZ_TASK_ATTEMPT_ID', dagID),
+ context: { name: 'task_attempts', type: 'TEZ_TASK_ATTEMPT_ID', part: 0 },
+ onItemFetched: processMultipleItems
+ }
+ ],
+ numItemTypesToDownload = itemsToDownload.length,
+ downloader = App.Helpers.io.fileDownloader(),
+ zipHelper = App.Helpers.io.zipHelper({
+ onProgress: function(filename, current, total) {
+ Em.Logger.debug('%@: %@ of %@'.fmt(filename, current, total));
+ },
+ onAdd: function(filename) {
+ Em.Logger.debug('adding %@ to Zip'.fmt(filename));
+ }
+ });
+
+ function getUrl(type, dagID, fromID) {
+ var url;
+ if (type == 'TEZ_DAG_ID') {
+ url = '%@/%@/%@'.fmt(baseurl, type, dagID);
+ } else {
+ url = '%@/%@?primaryFilter=TEZ_DAG_ID:%@&limit=%@'.fmt(baseurl, type, dagID, batchSize + 1);
+ if (!!fromID) {
+ url = '%@&fromId=%@'.fmt(url, fromID);
+ }
+ }
+ return url;
+ }
+
+ function checkIfAllDownloaded() {
+ numItemTypesToDownload--;
+ if (numItemTypesToDownload == 0) {
+ downloader.finish();
+ }
+ }
+
+ function processSingleItem(data, context) {
+ var obj = {};
+ obj[context.name] = data;
+
+ zipHelper.addFile({name: '%@.json'.fmt(context.name), data: JSON.stringify(obj, null, 2)});
+ checkIfAllDownloaded();
+ }
+
+ function processMultipleItems(data, context) {
+ var obj = {};
+ var nextBatchStart = undefined;
+
+ if (!$.isArray(data.entities)) {
+ throw "invalid data";
+ }
+
+ // need to handle no more entries , zero entries
+ if (data.entities.length > batchSize) {
+ nextBatchStart = data.entities.pop().entity;
+ }
+ obj[context.name] = data.entities;
+
+ zipHelper.addFile({name: '%@_part_%@.json'.fmt(context.name, context.part), data: JSON.stringify(obj, null, 2)});
+
+ if (!!nextBatchStart) {
+ context.part++;
+ downloader.queueItem({
+ url: getUrl(context.type, dagID, nextBatchStart),
+ context: context,
+ onItemFetched: processMultipleItems
+ });
+ } else {
+ checkIfAllDownloaded();
+ }
+ }
+
+ downloader.queueItems(itemsToDownload);
+
+ downloader.then(function() {
+ Em.Logger.info('Finished download');
+ zipHelper.close();
+ }).catch(function() {
+ Em.Logger.error('Failed to download');
+ zipHelper.abort();
+ });
+
+ var that = this;
+ zipHelper.then(function(zippedBlob) {
+ saveAs(zippedBlob, '%@.zip'.fmt(dagID));
+ if ($.isFunction(opts.onSuccess)) {
+ opts.onSuccess();
+ }
+ }).catch(function() {
+ Em.Logger.error('zip Failed');
+ if ($.isFunction(opts.onFailure)) {
+ opts.onFailure();
+ }
+ });
+
+ return {
+ cancel: function() {
+ downloader.cancel();
+ }
+ }
+ },
+
+ dagStatusUIOptions: [
+ { label: 'All', id: null },
+ { label: 'Submitted', id: 'SUBMITTED' },
+ { label: 'Running', id: 'RUNNING' },
+ { label: 'Succeeded', id: 'SUCCEEDED' },
+ { label: 'Failed', id: 'FAILED' },
+ { label: 'Killed', id: 'KILLED' },
+ { label: 'Error', id: 'ERROR' },
+ ],
+
+ vertexStatusUIOptions: [
+ { label: 'All', id: null },
+ { label: 'Running', id: 'RUNNING' },
+ { label: 'Succeeded', id: 'SUCCEEDED' },
+ { label: 'Failed', id: 'FAILED' },
+ { label: 'Killed', id: 'KILLED' },
+ { label: 'Error', id: 'ERROR' },
+ ],
+
+ taskStatusUIOptions: [
+ { label: 'All', id: null },
+ { label: 'Running', id: 'SCHEDULED' },
+ { label: 'Succeeded', id: 'SUCCEEDED' },
+ { label: 'Failed', id: 'FAILED' },
+ { label: 'Killed', id: 'KILLED' },
+ ],
+
+ taskAttemptStatusUIOptions: [
+ { label: 'All', id: null },
+ { label: 'Running', id: 'RUNNING' },
+ { label: 'Succeeded', id: 'SUCCEEDED' },
+ { label: 'Failed', id: 'FAILED' },
+ { label: 'Killed', id: 'KILLED' },
+ ],
+
+ defaultQueryParamsConfig: {
+ refreshModel: true,
+ replace: true
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/mixins/data-array-loader-minxin.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/mixins/data-array-loader-minxin.js b/tez-ui/src/main/webapp/app/scripts/mixins/data-array-loader-minxin.js
new file mode 100644
index 0000000..977143c
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/mixins/data-array-loader-minxin.js
@@ -0,0 +1,117 @@
+/**
+ * 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.
+ */
+
+var dataCache = {};
+
+App.DataArrayLoaderMixin = Em.Mixin.create({
+ data: [],
+ loading: false,
+
+ entityType: null,
+ filterEntityType: null,
+ filterEntityId: null,
+
+ isRefreshable: true,
+
+ _cacheKey: function () {
+ return [
+ this.get('filterEntityType'),
+ this.get('filterEntityId'),
+ this.get('entityType'),
+ ].join(':');
+ }.property('filterEntityType', 'filterEntityId', 'entityType'),
+
+ getFilter: function (limit) {
+ return {
+ limit: limit || Number.MAX_SAFE_INTEGER - 1,
+ primaryFilter: '%@:%@'.fmt(
+ App.Helpers.misc.getTimelineFilterForType(this.get('filterEntityType')),
+ this.get('filterEntityId')
+ )
+ };
+ },
+
+ loadData: function (skipCache) {
+ var data;
+
+ if(this.get('loading')) {
+ return false;
+ }
+
+ if(!skipCache) {
+ data = dataCache[this.get('_cacheKey')];
+ }
+
+ if(data && data.get('content.length')) {
+ this.set('data', data);
+ }
+ else {
+ this.loadAllData();
+ }
+
+ return true;
+ },
+
+ loadAllData: function () {
+ this.set('loading', true);
+
+ // Load all rows
+ return this.beforeLoad().
+ then(this.load.bind(this, this.getFilter())).
+ then(this.afterLoad.bind(this)).
+ then(this.cacheData.bind(this)).
+ then(this.set.bind(this, 'loading', false)).
+ catch(this.errorHandler.bind(this));
+ },
+
+ beforeLoad: function () {
+ return new Em.RSVP.resolve();
+ },
+
+ load: function (filter) {
+ var entityType = this.get('entityType'),
+ store = this.get('store'),
+ data = dataCache[this.get('_cacheKey')];
+
+ if(data) {
+ data.toArray().forEach(function (record) {
+ record.unloadRecord();
+ });
+ dataCache[this.get('_cacheKey')] = null;
+ }
+
+ return store.findQuery(entityType, filter).
+ then(this.set.bind(this, 'data')).
+ catch(this.errorHandler.bind(this));
+ },
+
+ cacheData: function () {
+ dataCache[this.get('_cacheKey')] = this.get('data');
+ },
+
+ errorHandler: function (error) {
+ Em.Logger.error(error);
+ var err = App.Helpers.misc.formatError(error, 'Error while loading ' + this.get('entityType'));
+ var msg = 'Error code: %@, message: %@'.fmt(err.errCode, err.msg);
+ App.Helpers.ErrorBar.getInstance().show(msg, err.details);
+ },
+
+ afterLoad: function () {
+ return new Em.RSVP.resolve();
+ },
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/models/dag.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/models/dag.js b/tez-ui/src/main/webapp/app/scripts/models/dag.js
index b86578c..05e356b 100644
--- a/tez-ui/src/main/webapp/app/scripts/models/dag.js
+++ b/tez-ui/src/main/webapp/app/scripts/models/dag.js
@@ -333,6 +333,10 @@ App.Task = App.AbstractEntity.extend({
endTime: DS.attr('number'),
+ duration: function () {
+ return App.Helpers.date.duration(this.get('startTime'), this.get('endTime'))
+ }.property('startTime', 'endTime'),
+
diagnostics: DS.attr('string'),
numAttempts: DS.attr('number'),
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/router.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/router.js b/tez-ui/src/main/webapp/app/scripts/router.js
index 50d47fd..6de5a5d 100644
--- a/tez-ui/src/main/webapp/app/scripts/router.js
+++ b/tez-ui/src/main/webapp/app/scripts/router.js
@@ -285,8 +285,19 @@ App.TezAppConfigsRoute = Em.Route.extend({
/* --- Shared routes --- */
-App.DagTasksRoute =
- App.DagVerticesRoute =
+App.DagTasksRoute = Em.Route.extend({
+ renderTemplate: function () {
+ this.render('common/table');
+ },
+ setupController: function (controller, model) {
+ this._super(controller, model);
+ if(controller.loadData) {
+ controller.loadData();
+ }
+ }
+});
+
+App.DagVerticesRoute =
App.DagTaskAttemptsRoute =
App.VertexTasksRoute =
App.VertexTaskAttemptsRoute =
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/scripts/views/extra-table-buttons-view.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/scripts/views/extra-table-buttons-view.js b/tez-ui/src/main/webapp/app/scripts/views/extra-table-buttons-view.js
new file mode 100644
index 0000000..422a755
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/scripts/views/extra-table-buttons-view.js
@@ -0,0 +1,23 @@
+/**
+ * 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.ExtraTableButtonsView = Ember.View.extend({
+ templateName: 'views/extra-table-buttons',
+
+ classNames: ['extra-table-buttons']
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/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 0fee7c0..9bf4b61 100644
--- a/tez-ui/src/main/webapp/app/styles/colors.less
+++ b/tez-ui/src/main/webapp/app/styles/colors.less
@@ -18,11 +18,16 @@
// Colors
@logo-orange: #D27A22;
+
@bg-lite: #f5f5f5;
@bg-liter: #f5f5f5;
-@border-lite: #e5e5e5;
@bg-red-light: #FFE6E6;
+@bg-grey: #f0f0f0;
+
+@border-lite: #e5e5e5;
+@border-color: #dcdcdc;
+
@white: #fff;
@text-color: #666666;
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/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 c800ab2..870e2ec 100644
--- a/tez-ui/src/main/webapp/app/styles/main.less
+++ b/tez-ui/src/main/webapp/app/styles/main.less
@@ -30,6 +30,9 @@ body, html, body > .ember-view {
height: 100%;
overflow: visible;
}
+body, html {
+ min-width: 1024px;
+}
// Styles used in both standalone and wrapped modes
.standalone, .wrapped {
@@ -96,10 +99,15 @@ body, html, body > .ember-view {
.standalone {
height: 100%;
- a {
+ a, .pagination > li > a, .btn-default, .clickable {
color: @logo-orange;
}
+ .is-current {
+ color: white;
+ background-color: @logo-orange;
+ }
+
#top-nav {
a.logo {
img {
@@ -159,6 +167,11 @@ body, html, body > .ember-view {
#top-nav, .footer, .push {
display: none;
}
+
+ .is-current {
+ color: white;
+ background-color: @brand-primary;
+ }
}
.error-bar {
@@ -519,6 +532,199 @@ div.indent {
}
.table-container {
+ .use-gpu;
+
+ margin: 10px 0px;
+
+ .table-header {
+ padding: 5px;
+
+ button:hover {
+ background-color: @bg-grey;
+ }
+
+ .table-message {
+ .inline-block;
+ font-size: 18px;
+ margin-top: 10px;
+ margin-left: 5px;
+ vertical-align: super;
+
+ overflow: hidden;
+ transform: translateZ(0);
+ }
+
+ .horizontal-half {
+ height: 33px;
+ white-space: nowrap;
+ }
+
+ .extra-table-buttons {
+ .inline-block;
+
+ .load-all {
+ .inline-block;
+ .left-divider;
+
+ margin-left: 5px;
+ text-align: center;
+
+ :first-child {
+ margin-bottom: -3px;
+ font-size: .85em;
+ color: red;
+ }
+ }
+
+ .column-selector-button {
+ .fa-action;
+ .fa-icon(cog);
+ .left-divider;
+ .inline-block;
+
+ padding-top: 5px;
+ height: 36px;
+ }
+ }
+ }
+
+ .waiting {
+ .fa;
+ .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;
+ }
+ }
+ }
+
+ .table-body-container{
+ border: 1px solid @border-color;
+ border-radius: 5px;
+
+ margin: 5px 0px;
+
+ overflow: auto;
+
+ .table-body {
+ .noise-background;
+ white-space: nowrap;
+ font-size: 0;
+
+ .table-column {
+ background-color: white;
+ display: inline-block;
+ min-width: 150px;
+ border-left: 1px solid @border-color;
+
+ &.first-item {
+ border-left: none;
+ }
+
+ .table-header-cell, .table-cell {
+ font-size: 13px;
+ padding: 5px;
+ position: relative;
+
+ .cell-content {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ height: 18px;
+ }
+
+ .resize-column {
+ .fa;
+ .fa-icon(ellipsis-v);
+
+ cursor: col-resize;
+ position: absolute;
+ right: 2px;
+ top: 10px;
+
+ opacity: .2;
+ }
+ }
+
+ .table-header-cell {
+ font-weight: bold;
+
+ padding-right: 15px;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+
+ background-color: @bg-grey;
+ border-bottom: 1px solid @border-color;
+ }
+
+ .table-cell {
+ border-top: 1px dotted @border-color;
+
+ &.first-item {
+ border-top: none;
+ }
+ }
+ }
+ }
+ }
+}
+
+.ember-table-container {
min-height: 20px;
width: 100%;
overflow: auto;
@@ -532,6 +738,23 @@ div.indent {
}
}
+.filter-cell, {
+ left: 0px;
+ top: 0px;
+ .sort, .filter {
+ position: absolute;
+ }
+ .filter {
+ left: 5px;
+ right: 20px;
+ }
+ .sort {
+ cursor: pointer;
+ top: 7px;
+ right: 5px;
+ }
+}
+
.input-dirty {
background-color: yellow;
}
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/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 617c87f..cebd837 100644
--- a/tez-ui/src/main/webapp/app/styles/shared.less
+++ b/tez-ui/src/main/webapp/app/styles/shared.less
@@ -43,4 +43,28 @@
.no-wrap {
white-space: nowrap;
+}
+
+.align-top{
+ vertical-align: top;
+}
+
+.inline-block {
+ display: inline-block;
+}
+
+.noise-background {
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAMAAAAp4XiDAAAAUVBMVEWFhYWDg4N3d3dtbW17e3t1dXWBgYGHh4d5eXlzc3OLi4ubm5uVlZWPj4+NjY19fX2JiYl/f39ra2uRkZGZmZlpaWmXl5dvb29xcXGTk5NnZ2c8TV1mAAAAG3RSTlNAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAvEOwtAAAFVklEQVR4XpWWB67c2BUFb3g557T/hRo9/WUMZHlgr4Bg8Z4qQgQJlHI4A8SzFVrapvmTF9O7dmYRFZ60YiBhJRCgh1FYhiLAmdvX0CzTOpNE77ME0Zty/nWWzchDtiqrmQDeuv3powQ5ta2eN0FY0InkqDD73lT9c9lEzwUNqgFHs9VQce3TVClFCQrSTfOiYkVJQBmpbq2L6iZavPnAPcoU0dSw0SUTqz/GtrGuXfbyyBniKykOWQWGqwwMA7QiYAxi+IlPdqo+hYHnUt5ZPfnsHJyNiDtnpJyayNBkF6cWoYGAMY92U2hXHF/C1M8uP/ZtYdiuj26UdAdQQSXQErwSOMzt/XWRWAz5GuSBIkwG1H3FabJ2OsUOUhGC6tK4EMtJO0ttC6IBD3kM0ve0tJwMdSfjZo+EEISaeTr9P3wYrGjXqyC1krcKdhMpxEnt5JetoulscpyzhXN5FRpuPHvbeQaKxFAEB6EN+cYN6xD7RYGpXpNndMmZgM5Dcs3YSNFDHUo2LGfZuukSWyUYirJAdYbF3MfqEKmjM+I2EfhA94iG3L7uKrR+GdWD73ydlIB+6hgref1QTlmgmbM3/LeX5GI1Ux1RWpgxpLuZ2+I+IjzZ8wqE4nilvQdkUdfhzI5QDWy+kw5Wgg2pGpeEVeCCA7b85BO3F9DzxB3cdqvBzWcmzbyMiqhzuYqtHRVG2y4x+KOlnyqla8AoWWpuBoY
RxzXrfKuILl6SfiWCbjxoZJUaCBj1CjH7GIaDbc9kqBY3W/Rgjda1iqQcOJu2WW+76pZC9QG7M00dffe9hNnseupFL53r8F7YHSwJWUKP2q+k7RdsxyOB11n0xtOvnW4irMMFNV4H0uqwS5ExsmP9AxbDTc9JwgneAT5vTiUSm1E7BSflSt3bfa1tv8Di3R8n3Af7MNWzs49hmauE2wP+ttrq+AsWpFG2awvsuOqbipWHgtuvuaAE+A1Z/7gC9hesnr+7wqCwG8c5yAg3AL1fm8T9AZtp/bbJGwl1pNrE7RuOX7PeMRUERVaPpEs+yqeoSmuOlokqw49pgomjLeh7icHNlG19yjs6XXOMedYm5xH2YxpV2tc0Ro2jJfxC50ApuxGob7lMsxfTbeUv07TyYxpeLucEH1gNd4IKH2LAg5TdVhlCafZvpskfncCfx8pOhJzd76bJWeYFnFciwcYfubRc12Ip/ppIhA1/mSZ/RxjFDrJC5xifFjJpY2Xl5zXdguFqYyTR1zSp1Y9p+tktDYYSNflcxI0iyO4TPBdlRcpeqjK/piF5bklq77VSEaA+z8qmJTFzIWiitbnzR794USKBUaT0NTEsVjZqLaFVqJoPN9ODG70IPbfBHKK+/q/AWR0tJzYHRULOa4MP+W/HfGadZUbfw177G7j/OGbIs8TahLyynl4X4RinF793Oz+BU0saXtUHrVBFT/DnA3ctNPoGbs4hRIjTok8i+algT1lTHi4SxFvONKNrgQFAq2/gFnWMXgwffgYMJpiKYkmW3tTg3ZQ9Jq+f8XN+A5eeUKHWvJWJ2sgJ1Sop+wwhqFVijqWaJhwtD8MNlSBeWNNWTa5Z5kPZw5+LbVT99wqTdx29lMUH4OIG/D86ruKEauBjvH5xy6um/Sfj7ei6UUVk4AIl3MyD4MSSTOFgSwsH/QJWaQ5as7ZcmgBZkzjjU1UrQ74ci1gWBCSGHtuV1H2mhSnO3Wp/3fEV5a+4
wz//6qy8JxjZsmxxy5+4w9CDNJY09T072iKG0EnOS0arEYgXqYnXcYHwjTtUNAcMelOd4xpkoqiTYICWFq0JSiPfPDQdnt+4/wuqcXY47QILbgAAAABJRU5ErkJggg==);
+}
+
+.absolute {
+ position: absolute;
+}
+
+.use-gpu {
+ -webkit-transform: translateZ(0);
+ -moz-transform: translateZ(0);
+ -ms-transform: translateZ(0);
+ -o-transform: translateZ(0);
+ transform: translateZ(0);
}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/common/table.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/common/table.hbs b/tez-ui/src/main/webapp/app/templates/common/table.hbs
new file mode 100644
index 0000000..2c54903
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/common/table.hbs
@@ -0,0 +1,47 @@
+{{!
+* 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.
+}}
+
+{{#unless loading}}
+ {{#if data.length}}
+ {{load-time-component
+ isRefreshable=isRefreshable
+ time=data.content.0.timeStamp
+ refresh='refresh'
+ }}
+
+ {{basic-table-component
+ columns=columns
+ rows=data.content
+
+ extraHeaderItem=App.ExtraTableButtonsView
+ statusMessage=statusMessage
+
+ enablePagination=true
+
+ pageNumBinding='pageNum'
+ rowCountBinding='rowCount'
+ }}
+ {{else}}
+ <h1>No records available!</n1>
+ {{/if}}
+{{else}}
+ {{partial 'partials/loading-spinner'}}
+ <div class="text-align-center">
+ {{statusMessage}}
+ </div>
+{{/unless}}
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/components/basic-table.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/basic-table.hbs b/tez-ui/src/main/webapp/app/templates/components/basic-table.hbs
new file mode 100644
index 0000000..ac4a466
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/components/basic-table.hbs
@@ -0,0 +1,58 @@
+{{!
+* 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.
+}}
+
+<div class='table-container'>
+ {{#if _showHeader}}
+ <div class='table-header'>
+ <div class="horizontal-half align-top">
+ </div><div class="horizontal-half align-top align-children-right">
+ {{#if enablePagination}}
+ {{view App.BasicTableComponent.PaginationView pageNum=pageNum totalPages=totalPages}}
+ {{/if}}
+ {{#if extraHeaderItem}}
+ {{view extraHeaderItem}}
+ {{/if}}
+ </div>
+ </div>
+ {{/if}}
+ <div class='table-body-container'>
+ <div class='table-body'>
+ {{#each column in _columns}}
+ <div {{bind-attr
+ style=column.customStyle
+ class=":table-column _view.contentIndex::first-item"
+ }}>
+ {{view column.headerCellView}}
+ {{#each row in _rows}}
+ <div class='table-cell {{unbound firstItemCSS _view}}'>
+ {{view column.cellView row=row}}
+ </div>
+ {{/each}}
+ </div>
+ {{/each}}
+ </div>
+ </div>
+ <div class='table-footer'>
+ <div class="horizontal-half align-top">
+ </div><div class="horizontal-half align-top align-children-right">
+ {{#if hasPageNavOnFooter}}
+ {{view App.BasicTableComponent.PaginationView pageNum=pageNum totalPages=totalPages}}
+ {{/if}}
+ </div>
+ </div>
+</div>
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/components/basic-table/basic-cell.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/basic-table/basic-cell.hbs b/tez-ui/src/main/webapp/app/templates/components/basic-table/basic-cell.hbs
new file mode 100644
index 0000000..370637b
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/components/basic-table/basic-cell.hbs
@@ -0,0 +1,19 @@
+{{!
+* 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.
+}}
+
+{{unbound view.cellContent}}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/components/basic-table/header-cell.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/basic-table/header-cell.hbs b/tez-ui/src/main/webapp/app/templates/components/basic-table/header-cell.hbs
new file mode 100644
index 0000000..1159524
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/components/basic-table/header-cell.hbs
@@ -0,0 +1,24 @@
+{{!
+* 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.
+}}
+
+<div class='table-header-cell'>
+ <div class='cell-content'>
+ {{unbound column.headerCellName}}
+ </div>
+ <i class="resize-column" {{action 'startColResize' on=mouseDown target='view'}} ></i>
+</div>
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/components/basic-table/linked-cell.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/basic-table/linked-cell.hbs b/tez-ui/src/main/webapp/app/templates/components/basic-table/linked-cell.hbs
new file mode 100644
index 0000000..3297ad7
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/components/basic-table/linked-cell.hbs
@@ -0,0 +1,25 @@
+{{!
+* 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.
+}}
+
+{{#if view.cellContent._notAvailable}}
+ {{view.cellContent}}
+{{else}}
+ {{#link-to view.cellContent.linkTo view.cellContent.entityId}}
+ {{view.cellContent.displayText}}
+ {{/link-to}}
+{{/if}}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/components/basic-table/logs-cell.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/basic-table/logs-cell.hbs b/tez-ui/src/main/webapp/app/templates/components/basic-table/logs-cell.hbs
new file mode 100644
index 0000000..092b6ee
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/components/basic-table/logs-cell.hbs
@@ -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.
+}}
+
+<span class="ember-table-content">
+ {{#if view.cellContent.isPending}}
+ <i class="waiting absolute"></i>
+ {{else}}
+ {{#if view.cellContent._notAvailable}}
+ {{view.cellContent}}
+ {{else}}
+ {{#if view.cellContent.viewUrl}}
+ <a target="_blank" href="//{{unbound view.cellContent.viewUrl}}">View</a>
+
+ {{/if}}
+ {{#if view.cellContent.downloadUrl}}
+ <a target="_blank" href="{{unbound view.cellContent.downloadUrl}}?start=0" download type="application/octet-stream">Download</a>
+ {{/if}}
+ {{/if}}
+ {{/if}}
+</span>
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/components/basic-table/pagination-view.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/basic-table/pagination-view.hbs b/tez-ui/src/main/webapp/app/templates/components/basic-table/pagination-view.hbs
new file mode 100644
index 0000000..808fe9d
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/components/basic-table/pagination-view.hbs
@@ -0,0 +1,38 @@
+{{!
+* 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.
+}}
+
+<ul class="page-list">
+ <li {{bind-attr class="view.atFirst::clickable"}} {{action 'changePage' 1}}>
+ First page
+ </li>
+ {{#each page in view._possiblePages}}
+ <li {{bind-attr class="page.isCurrent:is-current:clickable"}} {{action 'changePage' page.pageNum}}>
+ {{page.pageNum}}
+ </li>
+ {{/each}}
+ <li {{bind-attr class="view.atLast::clickable"}} {{action 'changePage' view.totalPages}}>
+ Last page - {{view.totalPages}}
+ </li>
+</ul>
+<div class='row-select'>
+ <div>Rows</div>
+ {{view Ember.Select
+ content=rowCountOptions
+ value=rowCount
+ }}
+</div>
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/components/basic-table/status-cell.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/basic-table/status-cell.hbs b/tez-ui/src/main/webapp/app/templates/components/basic-table/status-cell.hbs
new file mode 100644
index 0000000..a7caa35
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/components/basic-table/status-cell.hbs
@@ -0,0 +1,29 @@
+{{!
+* 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.
+}}
+
+{{#if view.cellContent._notAvailable}}
+ {{view.cellContent}}
+{{else}}
+ <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>
+{{/if}}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/components/basic-table/task-actions-cell.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/basic-table/task-actions-cell.hbs b/tez-ui/src/main/webapp/app/templates/components/basic-table/task-actions-cell.hbs
new file mode 100644
index 0000000..b914b82
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/components/basic-table/task-actions-cell.hbs
@@ -0,0 +1,26 @@
+{{!
+* 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.
+}}
+
+{{#if view.cellContent._notAvailable}}
+ {{view.cellContent}}
+{{else}}
+ <span class="ember-table-content">
+ {{#link-to "task.counters" view.cellContent}}counters{{/link-to}}
+ {{#link-to "task.attempts" view.cellContent}}attempts{{/link-to}}
+ </span>
+{{/if}}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/9316fe62/tez-ui/src/main/webapp/app/templates/views/extra-table-buttons.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/views/extra-table-buttons.hbs b/tez-ui/src/main/webapp/app/templates/views/extra-table-buttons.hbs
new file mode 100644
index 0000000..98099db
--- /dev/null
+++ b/tez-ui/src/main/webapp/app/templates/views/extra-table-buttons.hbs
@@ -0,0 +1,19 @@
+{{!
+ * 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.
+}}
+
+<i class='column-selector-button' {{action 'selectColumns' target=targetObject}}></i>