You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tez.apache.org by je...@apache.org on 2014/12/10 04:33:35 UTC
[12/53] tez git commit: TEZ-1605. Landing page for Tez UI (Prakash
Ramachandran via jeagles)
TEZ-1605. Landing page for Tez UI (Prakash Ramachandran via jeagles)
Project: http://git-wip-us.apache.org/repos/asf/tez/repo
Commit: http://git-wip-us.apache.org/repos/asf/tez/commit/f6d85173
Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/f6d85173
Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/f6d85173
Branch: refs/heads/master
Commit: f6d851730a204738ec77c57f49af599c1fb11a8a
Parents: c9fefa6
Author: Jonathan Eagles <je...@gmail.com>
Authored: Fri Oct 10 10:40:32 2014 -0500
Committer: Jonathan Eagles <je...@gmail.com>
Committed: Fri Oct 10 10:40:32 2014 -0500
----------------------------------------------------------------------
tez-ui/Gruntfile.js | 11 +-
tez-ui/README.TXT | 4 +-
tez-ui/app/index.html | 1 +
tez-ui/app/scripts/app.js | 2 +-
tez-ui/app/scripts/components/counter-table.js | 83 ++++++
tez-ui/app/scripts/components/page-nav.js | 6 +-
tez-ui/app/scripts/components/tasks-view.js | 4 +
.../app/scripts/controllers/dag_controller.js | 8 +-
tez-ui/app/scripts/controllers/dag_counters.js | 23 ++
.../scripts/controllers/dag_index_controller.js | 85 +++---
.../app/scripts/controllers/dags_controller.js | 56 ++--
.../controllers/show_tasks_view_controller.js | 135 ++++++++++
.../controllers/task_attempt_controller.js | 39 +++
.../app/scripts/controllers/task_controller.js | 39 +++
.../controllers/task_index_controller.js | 30 +++
.../app/scripts/controllers/tasks_controller.js | 131 +++++++++
tez-ui/app/scripts/helpers/ajax.js | 179 -------------
tez-ui/app/scripts/helpers/handlebarHelpers.js | 15 +-
tez-ui/app/scripts/helpers/misc.js | 57 ++++
tez-ui/app/scripts/mappers/dag_mapper.js | 56 ----
.../app/scripts/models/TimelineRestAdapter.js | 263 +++++++++++++------
tez-ui/app/scripts/models/dag.js | 14 +
tez-ui/app/scripts/models/task_attempt.js | 6 +-
tez-ui/app/scripts/router.js | 39 ++-
tez-ui/app/scripts/views/show_tasks_view.js | 81 ++++++
tez-ui/app/scripts/views/tasks_view.js | 23 ++
tez-ui/app/styles/main.css | 70 -----
tez-ui/app/styles/main.less | 133 ++++++++++
tez-ui/app/templates/components/page-nav.hbs | 7 +-
tez-ui/app/templates/dag.hbs | 11 +-
tez-ui/app/templates/dag/counters.hbs | 21 ++
tez-ui/app/templates/dag/index.hbs | 122 ++++++---
tez-ui/app/templates/dag/vertex.hbs | 2 +-
tez-ui/app/templates/dags.hbs | 4 +-
tez-ui/app/templates/task.hbs | 62 +++++
tez-ui/app/templates/task/counters.hbs | 21 ++
tez-ui/app/templates/task/index.hbs | 59 +++++
tez-ui/app/templates/taskAttempt/counters.hbs | 21 ++
tez-ui/app/templates/task_attempt.hbs | 51 ++++
tez-ui/app/templates/tasks.hbs | 58 ++++
tez-ui/app/templates/views/show_tasks.hbs | 38 +++
41 files changed, 1553 insertions(+), 517 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/Gruntfile.js
----------------------------------------------------------------------
diff --git a/tez-ui/Gruntfile.js b/tez-ui/Gruntfile.js
index a6d070a..3d3b96f 100644
--- a/tez-ui/Gruntfile.js
+++ b/tez-ui/Gruntfile.js
@@ -204,7 +204,8 @@ module.exports = function (grunt) {
'.tmp/styles/{,*/}*.css',
'<%= yeoman.app %>/styles/{,*/}*.css',
'<%= yeoman.app %>/bower_components/bootstrap/dist/css/bootstrap.css',
- '<%= yeoman.app %>/bower_components/ember-table/dist/ember-table.css'
+ '<%= yeoman.app %>/bower_components/ember-table/dist/ember-table.css',
+ '<%= yeoman.app %>/bower_components/font-awesome/css/font-awesome.css'
]
}
}
@@ -282,8 +283,8 @@ module.exports = function (grunt) {
{
expand: true,
flatten: true,
- src: '<%= yeoman.app %>/bower_components/font-awesome/font/*',
- dest: '<%= yeoman.dist %>/font/'
+ src: '<%= yeoman.app %>/bower_components/font-awesome/fonts/*',
+ dest: '<%= yeoman.dist %>/fonts/'
}
]
},
@@ -312,8 +313,8 @@ module.exports = function (grunt) {
{
expand: true,
flatten: true,
- src: '<%= yeoman.app %>/bower_components/font-awesome/font/*',
- dest: '.tmp/font/'
+ src: '<%= yeoman.app %>/bower_components/font-awesome/fonts/*',
+ dest: '.tmp/fonts/'
},
{
expand: true,
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/README.TXT
----------------------------------------------------------------------
diff --git a/tez-ui/README.TXT b/tez-ui/README.TXT
index 4e00df0..a633648 100644
--- a/tez-ui/README.TXT
+++ b/tez-ui/README.TXT
@@ -9,8 +9,8 @@ The timeline server (ATS) url by default points to http://localhost:8188. This c
changed to point to another host by editing the App.AtsBaseUrl entry in the
app/scripts/app.js file.
-For development run 'grunt serve'. This runs a dev server on port 9000.
-navigate to http://localhost:9000 if a browser does not open automatically.
+For development run 'grunt serve'. This runs a dev server on port 9001.
+navigate to http://localhost:9001 if a browser does not open automatically.
Any changes made will be live-reloaded on the browser.
For creating a distribution version, run 'grunt build'. The distributable
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/index.html
----------------------------------------------------------------------
diff --git a/tez-ui/app/index.html b/tez-ui/app/index.html
index 1ee7859..1653e94 100644
--- a/tez-ui/app/index.html
+++ b/tez-ui/app/index.html
@@ -47,6 +47,7 @@
<script src="bower_components/ember-json-mapper/ember-json-mapper.js"></script>
<script src="bower_components/ember-i18n/lib/i18n.js"></script>
<script src="bower_components/ember-addons.bs_for_ember/dist/js/bs-core.min.js"></script>
+ <script src="bower_components/ember-addons.bs_for_ember/dist/js/bs-basic.min.js"></script>
<script src="bower_components/ember-addons.bs_for_ember/dist/js/bs-button.min.js"></script>
<script src="bower_components/ember-addons.bs_for_ember/dist/js/bs-modal.min.js"></script>
<script src="bower_components/ember-addons.bs_for_ember/dist/js/bs-nav.min.js"></script>
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/app.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/app.js b/tez-ui/app/scripts/app.js
index d8b47d9..c06678e 100644
--- a/tez-ui/app/scripts/app.js
+++ b/tez-ui/app/scripts/app.js
@@ -42,8 +42,8 @@ App.Mappers = Em.Namespace.create();
require('scripts/translations');
require('scripts/mixins/*');
require('scripts/helpers/*');
-require('scripts/models/**/*');
require('scripts/views/**/*');
+require('scripts/models/**/*');
require('scripts/mappers/server_data_mapper.js');
require('scripts/mappers/**/*');
require('scripts/controllers/**/*');
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/components/counter-table.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/components/counter-table.js b/tez-ui/app/scripts/components/counter-table.js
new file mode 100644
index 0000000..2ee6b76
--- /dev/null
+++ b/tez-ui/app/scripts/components/counter-table.js
@@ -0,0 +1,83 @@
+/**
+ * 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.CounterTableComponent = Ember.Table.EmberTableComponent.extend({
+ hasFooter: false,
+ hasHeader: true,
+ forceFillColumns: true,
+ data: null,
+
+ columns: function() {
+ var groupColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'Group',
+ getCellContent: function(row) {
+ return row.get('counterGroup');
+ }
+ });
+
+ var nameColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'Counter Name',
+ tableCellViewClass: Em.Table.TableCell.extend({
+ template: Em.Handlebars.compile(
+ '<span {{bind-attr class=":ember-table-content view.cellContent.isCG:countertable-group-header:countertable-row"}}>\
+ {{view.cellContent.name}}\
+ </span>')
+ }),
+ getCellContent: function(row) {
+ return {
+ isCG: row.get('counters') != undefined,
+ name: row.get('name')
+ };
+ }
+ });
+
+ var valueColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'Value',
+ tableCellViewClass: Em.Table.TableCell.extend({
+ template: Em.Handlebars.compile(
+ '<span {{bind-attr class=":ember-table-content view.cellContent.isCG:countertable-group-header"}}>\
+ {{view.cellContent.value}}\
+ </span>')
+ }),
+ getCellContent: function(row) {
+ return {
+ isCG: row.get('counters') != undefined,
+ value: row.get('value')
+ };
+ }
+ });
+
+ return [nameColumn, valueColumn];
+ }.property(),
+
+ content: function() {
+ var allCounters = [];
+ if (!!this.data) {
+ this.data.forEach(function(cg){
+ allCounters.push(cg);
+ [].push.apply(allCounters, cg.get('counters').content);
+ });
+ }
+ return allCounters;
+ }.property('data'),
+});
+
+Em.Handlebars.helper('counter-table-component', App.CounterTableComponent);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/components/page-nav.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/components/page-nav.js b/tez-ui/app/scripts/components/page-nav.js
index b7c21a6..a6c0f68 100644
--- a/tez-ui/app/scripts/components/page-nav.js
+++ b/tez-ui/app/scripts/components/page-nav.js
@@ -17,6 +17,8 @@
*/
App.PageNavComponent = Em.Component.extend({
+ layoutName: 'components/page-nav',
+
actions: {
gotoNext: function() {
this.sendAction('navNext');
@@ -28,4 +30,6 @@ App.PageNavComponent = Em.Component.extend({
this.sendAction('navFirst');
}
}
-});
\ No newline at end of file
+});
+
+Em.Handlebars.helper('page-nav-component', App.PageNavComponent);
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/components/tasks-view.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/components/tasks-view.js b/tez-ui/app/scripts/components/tasks-view.js
new file mode 100644
index 0000000..494dcfa
--- /dev/null
+++ b/tez-ui/app/scripts/components/tasks-view.js
@@ -0,0 +1,4 @@
+App.ShowTasksComponent = Ember.Component.extend({
+ foo: function() {
+ }.on('didInsertElement')
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/dag_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/dag_controller.js b/tez-ui/app/scripts/controllers/dag_controller.js
index 1e2e4f2..414bc1d 100644
--- a/tez-ui/app/scripts/controllers/dag_controller.js
+++ b/tez-ui/app/scripts/controllers/dag_controller.js
@@ -17,9 +17,9 @@
*/
App.DagController = Em.ObjectController.extend(App.Helpers.DisplayHelper, {
- controllerName: "DagsController",
+ controllerName: 'DagController',
- pageTitle: "Dag",
+ pageTitle: 'Dag',
loading: true,
@@ -29,11 +29,11 @@ App.DagController = Em.ObjectController.extend(App.Helpers.DisplayHelper, {
pageSubTitle: function() {
return this.get('name');
- }.property(),
+ }.property('name'),
childDisplayViews: [
Ember.Object.create({title: 'Details', linkTo: 'dag.index'}),
- Ember.Object.create({title: 'Vertex', linkTo: 'dag.vertex'}),
+ Ember.Object.create({title: 'Counters', linkTo: 'dag.counters'}),
Ember.Object.create({title: 'Swimlane', linkTo: 'dag.swimlane'})
],
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/dag_counters.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/dag_counters.js b/tez-ui/app/scripts/controllers/dag_counters.js
new file mode 100644
index 0000000..80aee92
--- /dev/null
+++ b/tez-ui/app/scripts/controllers/dag_counters.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.
+ */
+
+ //TODO: watch individual counters.
+/*App.DagCountersController = Em.ObjectController.extend({
+ controllerName: 'DagIndexController',
+
+});*/
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/dag_index_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/dag_index_controller.js b/tez-ui/app/scripts/controllers/dag_index_controller.js
index 4ecae7d..c9cc99e 100644
--- a/tez-ui/app/scripts/controllers/dag_index_controller.js
+++ b/tez-ui/app/scripts/controllers/dag_index_controller.js
@@ -16,48 +16,45 @@
* limitations under the License.
*/
+ require('scripts/controllers/show_tasks_view_controller');
+
+ //TODO: watch individual counters.
App.DagIndexController = Em.ObjectController.extend({
- controllerName: "DagsController",
-
- counterTableColumns: function() {
- var groupColumn = Em.Table.ColumnDefinition.create({
- textAlign: 'text-align-left',
- headerCellName: 'Group',
- getCellContent: function(row) {
- return row.get('counterGroup');
- }
- });
-
- var nameColumn = Em.Table.ColumnDefinition.create({
- textAlign: 'text-align-left',
- headerCellName: 'Counter Name',
- getCellContent: function(row) {
- return row.get('name');
- }
- });
-
- var valueColumn = Em.Table.ColumnDefinition.create({
- textAlign: 'text-align-left',
- headerCellName: 'Counter Name',
- getCellContent: function(row) {
- return row.get('value');
- }
- });
-
- return [groupColumn, nameColumn, valueColumn];
- }.property(),
-
- counterContent: function() {
- var allCounters = [];
- this.get('content').get('counterGroups').forEach(function(cg){
- cg.get('counters').forEach(function(counter){
- allCounters.push({
- counterGroup: cg.get('displayName'),
- name: counter.get('displayName'),
- value: counter.get('value')
- });
- });
- });
- return allCounters;
- }.property(),
-});
\ No newline at end of file
+ controllerName: 'DagIndexController',
+
+ taskIconStatus: function() {
+ return App.Helpers.misc.getStatusClassForEntity(this.get('model'));
+ }.property('id', 'status', 'counterGroups'),
+
+ totalTasks: function() {
+ return App.Helpers.misc.getCounterValueForDag(this.get('counterGroups'),
+ this.get('id'), 'org.apache.tez.common.counters.DAGCounter', 'TOTAL_LAUNCHED_TASKS')
+ }.property('id', 'counterGroups'),
+
+ sucessfulTasks: function() {
+ return App.Helpers.misc.getCounterValueForDag(this.get('counterGroups'), this.get('id'),
+ 'org.apache.tez.common.counters.DAGCounter', 'NUM_SUCCEEDED_TASKS')
+ }.property('id', 'counterGroups'),
+
+ failedTasks: function() {
+ return App.Helpers.misc.getCounterValueForDag(this.get('counterGroups'), this.get('id'),
+ 'org.apache.tez.common.counters.DAGCounter', 'NUM_FAILED_TASKS')
+ }.property('id', 'counterGroups'),
+
+ killedTasks: function() {
+ return App.Helpers.misc.getCounterValueForDag(this.get('counterGroups'), this.get('id'),
+ 'org.apache.tez.common.counters.DAGCounter', 'NUM_KILLED_TASKS')
+ }.property('id', 'counterGroups'),
+
+ hasFailedTasks: function() {
+ return this.get('failedTasks') > 0;
+ }.property('id', 'counterGroups'),
+
+ actions: {
+ showFailedTasks: function() {
+ alert('not implemented');
+ }
+ },
+
+ showTasksViewController: App.ShowTasksViewController.create()
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/dags_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/dags_controller.js b/tez-ui/app/scripts/controllers/dags_controller.js
index 70ef7f3..e92f281 100644
--- a/tez-ui/app/scripts/controllers/dags_controller.js
+++ b/tez-ui/app/scripts/controllers/dags_controller.js
@@ -17,11 +17,11 @@
*/
App.DagsController = Em.ArrayController.extend({
- controllerName: "DagsController",
+ controllerName: 'DagsController',
- pageTitle: "Dags",
+ pageTitle: 'Dags',
- pageSubTitle: "All Dags",
+ pageSubTitle: 'All Dags',
/* filtering and sorting related */
queryParams: {
@@ -138,49 +138,59 @@ App.DagsController = Em.ArrayController.extend({
/* table view for dags */
columns: function() {
+ var store = this.get('store');
+ var columnHelper = function(columnName, valName) {
+ return Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: columnName,
+ getCellContent: function(row) {
+ return row.get(valName);
+ }
+ });
+ }
+
var idColumn = Em.Table.ColumnDefinition.create({
textAlign: 'text-align-left',
headerCellName: 'Dag Id',
tableCellViewClass: Em.Table.TableCell.extend({
- template: Em.Handlebars.compile("{{#link-to 'dag' view.cellContent class='ember-table-content'}}{{view.cellContent}}{{/link-to}}")
+ template: Em.Handlebars.compile(
+ "{{#link-to 'dag' view.cellContent class='ember-table-content'}}{{view.cellContent}}{{/link-to}}")
}),
getCellContent: function(row) {
return row.get('id');
}
});
- var nameColumn = Em.Table.ColumnDefinition.create({
- textAlign: 'text-align-left',
- headerCellName: 'Name',
- getCellContent: function(row) {
- return row.get('name');
- }
- });
- var userColumn = Em.Table.ColumnDefinition.create({
- textAlign: 'text-align-left',
- headerCellName: 'Submitter',
- getCellContent: function(row) {
- return row.get('user');
- }
- });
+ var nameColumn = columnHelper('Name', 'name');
+ var userColumn = columnHelper('Submitter', 'user');
var statusColumn = Em.Table.ColumnDefinition.create({
textAlign: 'text-align-left',
headerCellName: 'Status',
+ 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>')
+ }),
getCellContent: function(row) {
- return row.get('status');
+ return {
+ status: row.get('status'),
+ statusIcon: App.Helpers.misc.getStatusClassForEntity(row)
+ };
}
});
var startTimeColumn = Em.Table.ColumnDefinition.create({
textAlign: 'text-align-left',
- headerCellName: 'SubmissionTime',
+ headerCellName: 'Submission Time',
getCellContent: function(row) {
return App.Helpers.date.dateFormat(row.get('startTime'));
}
});
- var appIdColumn = Em.Table.ColumnDefinition.create({
+ var appIdColumn = columnHelper('Application ID', 'applicationId');
+ var endTimeColumn = Em.Table.ColumnDefinition.create({
textAlign: 'text-align-left',
- headerCellName: 'Application Id',
+ headerCellName: 'End Time',
getCellContent: function(row) {
- return row.get('applicationId');
+ return App.Helpers.date.dateFormat(row.get('endTime'));
}
});
return [idColumn, nameColumn, userColumn, statusColumn, startTimeColumn, appIdColumn];
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/show_tasks_view_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/show_tasks_view_controller.js b/tez-ui/app/scripts/controllers/show_tasks_view_controller.js
new file mode 100644
index 0000000..d769200
--- /dev/null
+++ b/tez-ui/app/scripts/controllers/show_tasks_view_controller.js
@@ -0,0 +1,135 @@
+/**
+ * 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 parentTypeToATSType = {
+ dag: 'TEZ_DAG_ID',
+ task: 'TEZ_TASK_ID',
+ taskAttempt: 'TEZ_TASK_ATTEMPT_ID'
+};
+
+var childEntityTypeForParent = {
+ dag: 'task',
+ task: 'taskAttempt'
+}
+
+//TODO: This is generic view controller - name it so.
+App.ShowTasksViewController = Em.ObjectController.extend({
+ controllerName: 'ShowTasksViewController',
+
+ count: 10,
+
+ fromID: '',
+
+ fromTS: '',
+
+ /* There is currently no efficient way in ATS to get pagination data, so we fake one.
+ * 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
+ },
+
+ entities: [],
+ loading: true,
+
+ getChildEntityType: function(parentType) {
+ return childEntityTypeForParent[parentType];
+ },
+
+ sortedContent: function() {
+ var sorted = Em.ArrayController.create({
+ model: this.get('entities'),
+ sortProperties: ['startTime'],
+ sortAscending: false
+ });
+ this.updatePagination(sorted.toArray());
+ return sorted.slice(0, this.count);
+ }.property('entities'),
+
+ loadEntities: function() {
+ var that = this;
+ var parentEntityType = this.get('parentEntityType');
+ var childEntityType = childEntityTypeForParent[parentEntityType];
+ this.get('store').unloadAll(childEntityType);
+ this.get('store').findQuery(childEntityType, this.getFilterProperties()).then(function(entities){
+ that.set('entities', entities);
+ that.set('loading', false);
+ }).catch(function(jqXHR){
+ alert('failed');
+ });
+ }.observes('content.parentEntityID', 'fromID'),
+
+ 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');
+ }
+ this.set('navIDs.nextID', nextID);
+ }
+ },
+
+ hasPrev: function() {
+ return this.navIDs.prevIDs.length > 0;
+ }.property('navIDs.prevIDs.[]'),
+
+ 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);
+ },
+
+ // goto first page.
+ navigateFirst: function() {
+ var firstPageId = this.navIDs.prevIDs[0];
+ this.set('navIDs.prevIDs', []);
+ this.set('fromID', firstPageId);
+ this.set('loading', true);
+ },
+
+ // go to next page
+ navigateNext: function () {
+ this.navIDs.prevIDs.pushObject(this.navIDs.currentID);
+ this.set('fromID', this.get('navIDs.nextID'));
+ this.set('loading', true);
+ },
+ },
+
+ getFilterProperties: function() {
+ var params = {
+ primaryFilter: parentTypeToATSType[this.get('parentEntityType')] + ':' + this.get('parentEntityID'),
+ limit: this.count + 1
+ };
+
+ if (this.fromID) {
+ params['fromId'] = this.fromID;
+ }
+
+ return params;
+ },
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/task_attempt_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/task_attempt_controller.js b/tez-ui/app/scripts/controllers/task_attempt_controller.js
new file mode 100644
index 0000000..8fa290e
--- /dev/null
+++ b/tez-ui/app/scripts/controllers/task_attempt_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.TaskAttemptController = Em.ObjectController.extend(App.Helpers.DisplayHelper, {
+ controllerName: 'TaskAttemptController',
+
+ pageTitle: 'Task Attempt',
+
+ loading: true,
+
+ updateLoading: function() {
+ this.set('loading', false);
+ }.observes('content'),
+
+ pageSubTitle: function() {
+ return this.get('id');
+ }.property('id'),
+
+ childDisplayViews: [
+ Ember.Object.create({title: 'Details', linkTo: 'taskAttempt.index'}),
+ Ember.Object.create({title: 'Counters', linkTo: 'taskAttempt.counters'}),
+ ],
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/task_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/task_controller.js b/tez-ui/app/scripts/controllers/task_controller.js
new file mode 100644
index 0000000..ad3e455
--- /dev/null
+++ b/tez-ui/app/scripts/controllers/task_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.TaskController = Em.ObjectController.extend(App.Helpers.DisplayHelper, {
+ controllerName: 'TaskController',
+
+ pageTitle: 'Task',
+
+ loading: true,
+
+ updateLoading: function() {
+ this.set('loading', false);
+ }.observes('content'),
+
+ pageSubTitle: function() {
+ return this.get('id');
+ }.property('id'),
+
+ childDisplayViews: [
+ Ember.Object.create({title: 'Details', linkTo: 'task.index'}),
+ Ember.Object.create({title: 'Counters', linkTo: 'task.counters'}),
+ ],
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/task_index_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/task_index_controller.js b/tez-ui/app/scripts/controllers/task_index_controller.js
new file mode 100644
index 0000000..2cff0d5
--- /dev/null
+++ b/tez-ui/app/scripts/controllers/task_index_controller.js
@@ -0,0 +1,30 @@
+/**
+ * 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.
+ */
+
+ require('scripts/controllers/show_tasks_view_controller');
+
+ //TODO: watch individual counters.
+App.TaskIndexController = Em.ObjectController.extend({
+ controllerName: 'TaskIndexController',
+
+ taskIconStatus: function() {
+ return App.Helpers.misc.getStatusClassForEntity(this.get('model'));
+ }.property('id', 'status', 'counterGroups'),
+
+ showTasksViewController: App.ShowTasksViewController.create()
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/controllers/tasks_controller.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/controllers/tasks_controller.js b/tez-ui/app/scripts/controllers/tasks_controller.js
new file mode 100644
index 0000000..55b45a6
--- /dev/null
+++ b/tez-ui/app/scripts/controllers/tasks_controller.js
@@ -0,0 +1,131 @@
+/**
+ * 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.TasksController = Em.ArrayController.extend({
+ controllerName: 'TasksController',
+
+ pageTitle: 'Tasks',
+
+ pageSubTitle: 'All Tasks',
+
+ /* There is currently no efficient way in ATS to get pagination data, so we fake one.
+ * store the first task 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
+ },
+
+ sortedContent: function() {
+ var sorted = Em.ArrayController.create({
+ model: this.get('content'),
+ sortProperties: ['startTime'],
+ sortAscending: false
+ });
+ this.updatePagination(sorted.toArray());
+ return sorted.slice(0, this.count);
+ }.property('content.isUpdating', 'content.isLoading'),
+
+ updatePagination: function(currentPageTaskIDs) {
+ if (!!currentPageTaskIDs && currentPageTaskIDs.length > 0) {
+ this.set('navIDs.currentID', currentPageTaskIDs[0].id);
+ var nextID = undefined;
+ if (currentPageTaskIDs.length > this.count) {
+ // save the last id, so that we can use that as firt id on next page.
+ nextID = currentPageTaskIDs[this.count].id;
+ }
+ this.set('navIDs.nextID', nextID);
+ }
+ },
+
+ getFilterParams: function(params) {
+ //TODO: other parameters.
+ var filterParams = {};
+
+ if (params.dag_id) {
+ filterParams['primaryFilter'] = 'TEZ_DAG_ID:' + params.dag_id;
+ }
+
+ return filterParams;
+ },
+
+ /* table view for tasks */
+ columns: function() {
+ var store = this.get('store');
+ var columnHelper = function(columnName, valName) {
+ return Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: columnName,
+ getCellContent: function(row) {
+ return row.get(valName);
+ }
+ });
+ }
+
+ var idColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'Task Id',
+ tableCellViewClass: Em.Table.TableCell.extend({
+ template: Em.Handlebars.compile(
+ "{{#link-to 'task' view.cellContent class='ember-table-content'}}{{view.cellContent}}{{/link-to}}")
+ }),
+ getCellContent: function(row) {
+ return row.get('id');
+ }
+ });
+
+ var vertexColumn = columnHelper('Vertex ID', 'vertexID');
+
+ var startTimeColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'Submission Time',
+ getCellContent: function(row) {
+ return App.Helpers.date.dateFormat(row.get('startTime'));
+ }
+ });
+
+ var endTimeColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'End Time',
+ getCellContent: function(row) {
+ return App.Helpers.date.dateFormat(row.get('endTime'));
+ }
+ });
+
+ var statusColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'Status',
+ 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>')
+ }),
+ getCellContent: function(row) {
+ return {
+ status: row.get('status'),
+ statusIcon: App.Helpers.misc.getStatusClassForEntity(row)
+ };
+ }
+ });
+
+ return [idColumn, vertexColumn, startTimeColumn, endTimeColumn, statusColumn];
+ }.property(),
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/helpers/ajax.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/helpers/ajax.js b/tez-ui/app/scripts/helpers/ajax.js
deleted file mode 100644
index f50401e..0000000
--- a/tez-ui/app/scripts/helpers/ajax.js
+++ /dev/null
@@ -1,179 +0,0 @@
-/**
- * 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.
- */
-
-/**
- * Config for each ajax-request
- *
- * Fields example:
- * mock - testMode url
- * real - real url (without API prefix)
- * type - request type (also may be defined in the format method)
- * format - function for processing ajax params after default formatRequest. May be called with one or two parameters (data, opt). Return ajax-params object
- * testInProduction - can this request be executed on production tests (used only in tests)
- *
- * @type {Object}
- */
-var urls = {
- load_dags: {
- real: App.AtsBaseUrl + '/ws/v1/timeline/TEZ_DAG_ID/{queryParams}',
- mock: '',
- apiPrefix: ''
- },
-
- load_dag_details: {
- real: App.AtsBaseUrl + '/ws/v1/timeline/TEZ_DAG_ID/{dag_id}?fields=events,otherinfo,primaryfilters',
- mock: '',
- apiPrefix: ''
- },
-
- load_vertex_details: {
- real: App.AtsBaseUrl + '/ws/v1/timeline/TEZ_VERTEX_ID/?primaryFilter=TEZ_DAG_ID:{dag_id}'
- },
-
- load_task_attempts: {
- real: App.AtsBaseUrl + '/ws/v1/timeline/TEZ_TASK_ATTEMPT_ID/?primaryFilter=TEZ_DAG_ID:{dag_id}'
- },
-};
-
-/**
- * Replace data-placeholders to its values
- *
- * @param {String} url
- * @param {Object} data
- * @return {String}
- */
-var formatUrl = function (url, data) {
- if (!url) return null;
- var keys = url.match(/\{\w+\}/g);
- keys = (keys === null) ? [] : keys;
- if (keys) {
- keys.forEach(function (key) {
- var raw_key = key.substr(1, key.length - 2);
- var replace;
- if (!data || !data[raw_key]) {
- replace = '';
- }
- else {
- replace = data[raw_key];
- }
- url = url.replace(new RegExp(key, 'g'), replace);
- });
- }
- return url;
-};
-
-/**
- * this = object from config
- * @return {Object}
- */
-var formatRequest = function (data) {
- var opt = {
- type: this.type || 'GET',
- dataType: 'json',
- async: true,
- headers: this.headers
- };
- if (App.get('testMode')) {
- opt.url = formatUrl(this.mock ? this.mock : '', data);
- opt.type = 'GET';
- }
- else {
- var prefix = this.apiPrefix != null ? this.apiPrefix : App.get('urlPrefix');
- opt.url = prefix + formatUrl(this.real, data);
- }
-
- if (this.format) {
- jQuery.extend(opt, this.format(data, opt));
- }
- return opt;
-};
-
-/**
- * Wrapper for all ajax requests
- *
- * @type {Object}
- */
-var ajax = Em.Object.extend({
- /**
- * Send ajax request
- *
- * @param {Object} config
- * @return {$.ajax} jquery ajax object
- *
- * config fields:
- * name - url-key in the urls-object *required*
- * sender - object that send request (need for proper callback initialization) *required*
- * data - object with data for url-format
- * beforeSend - method-name for ajax beforeSend response callback
- * success - method-name for ajax success response callback
- * error - method-name for ajax error response callback
- */
- send: function (config) {
-
- Ember.assert('Ajax sender should be defined!', config.sender);
- Ember.assert('Invalid config.name provided - ' + config.name, urls[config.name]);
-
- var opt = {},
- params = {clusterName: App.get('clusterName')};
-
- if (config.data) {
- jQuery.extend(params, config.data);
- }
-
- opt = formatRequest.call(urls[config.name], params);
- opt.context = this;
-
- // object sender should be provided for processing beforeSend, success, error and complete responses
- opt.beforeSend = function (xhr) {
- if (config.beforeSend) {
- config.sender[config.beforeSend](opt, xhr, params);
- }
- };
-
- opt.success = function (data) {
- console.log("TRACE: The url is: " + opt.url);
- if (config.success) {
- config.sender[config.success](data, opt, params);
- }
- };
-
- opt.error = function (request, ajaxOptions, error) {
- if (config.error) {
- config.sender[config.error](request, ajaxOptions, error, opt, params);
- }
- };
-
- opt.complete = function (xhr, status) {
- if (config.complete) {
- config.sender[config.complete](xhr, status);
- }
- };
-
- return $.ajax(opt);
- },
-
- formatUrlFor: function(endpoint, data) {
- Ember.assert('Ajax sender should be defined!', !!endpoint);
- Ember.assert('Invalid config.name provided - ' + endpoint, urls[endpoint]);
-
- return formatUrl(urls[endpoint].real, data);
- }
-
-});
-
-App.ajax = ajax.create({});
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/helpers/handlebarHelpers.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/helpers/handlebarHelpers.js b/tez-ui/app/scripts/helpers/handlebarHelpers.js
index 5ed5e8e..72e3b0e 100644
--- a/tez-ui/app/scripts/helpers/handlebarHelpers.js
+++ b/tez-ui/app/scripts/helpers/handlebarHelpers.js
@@ -45,4 +45,17 @@ Em.Handlebars.helper('formatDuration', function(startTime, endTime) {
}
return App.Helpers.date.durationSummary(startTime, endTime);
-});
\ No newline at end of file
+});
+
+function replaceAll(str, str1, str2, ignore)
+{
+ return str.replace(new RegExp(str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g,"\\$&"),(ignore?"gi":"g")),(typeof(str2)=="string")?str2.replace(/\$/g,"$$$$"):str2);
+}
+
+//TODO: needs better indendation.
+Em.Handlebars.helper('formatDiagnostics', function(diagnostics) {
+ var x = replaceAll(diagnostics, '[', '<div class="indent"><i> </i>');
+ x = replaceAll(x, '],', '</div><i> </i>');
+ x = replaceAll(x, ']', '</div>');
+ return new Handlebars.SafeString(x);
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/helpers/misc.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/helpers/misc.js b/tez-ui/app/scripts/helpers/misc.js
new file mode 100644
index 0000000..1a5c4e8
--- /dev/null
+++ b/tez-ui/app/scripts/helpers/misc.js
@@ -0,0 +1,57 @@
+/**
+ * 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(dag) {
+ if (dag.get('status') == 'FAILED') {
+ return 'failure';
+ }
+
+ 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';
+ },
+
+ 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');
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/mappers/dag_mapper.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/mappers/dag_mapper.js b/tez-ui/app/scripts/mappers/dag_mapper.js
deleted file mode 100644
index aa862f9..0000000
--- a/tez-ui/app/scripts/mappers/dag_mapper.js
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * 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 jsonToDagMap = {
- id: 'entity',
- startTime: 'otherinfo.startTime', //TODO: what is the difference between this and the one in the otherinfo
- endTime: 'otherinfo.endTime',
- name: 'primaryfilters.dagName',
- user: 'primaryfilters.user',
- applicationId: 'otherinfo.applicationId',
- status: 'otherinfo.status',
- diagnostics: 'otherinfo.diagnostics'
-};
-
-App.Mappers.Dag = {
- mapSingle : function(json) {
- return Em.JsonMapper.map(json, jsonToDagMap);
- },
-
- mapMany : function(json) {
- if (Array.isArray(json.entities)) {
- return json.entities.map(this.mapSingle);
- }
-
- return [];
- }
-}
-
-App.Mappers.Vertex = {
- mapSingle: function(json) {
- return Em.JsonMapper.map(json, jsonToVertexMap);
- },
-
- mapMany: function(json) {
- if (Array.isArray(json.entities)) {
- return json.entities.map(this.mapSingle);
- }
-
- return [];
- }
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/models/TimelineRestAdapter.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/models/TimelineRestAdapter.js b/tez-ui/app/scripts/models/TimelineRestAdapter.js
index 58d8f4b..5133286 100644
--- a/tez-ui/app/scripts/models/TimelineRestAdapter.js
+++ b/tez-ui/app/scripts/models/TimelineRestAdapter.js
@@ -1,7 +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.
+ */
+
var typeToPathMap = {
dag: 'TEZ_DAG_ID',
vertex: 'TEZ_VERTEX_ID',
- taskAttempt: 'TEZ_TASK_ATTEMPT_ID',
+ task: 'TEZ_TASK_ID',
+ taskAttempt: 'TEZ_TASK_ATTEMPT_ID'
};
App.TimelineRESTAdapter = DS.RESTAdapter.extend({
@@ -15,12 +33,6 @@ App.TimelineRESTAdapter = DS.RESTAdapter.extend({
});
App.TimelineSerializer = DS.RESTSerializer.extend({
- primaryKey: 'entity',
-
- attrs: {
- key: 'entity',
- },
-
extractSingle: function(store, primaryType, rawPayload, recordId) {
// rest serializer expects singular form of model as the root key.
var payload = {};
@@ -36,6 +48,46 @@ App.TimelineSerializer = DS.RESTSerializer.extend({
return this._super(store, primaryType, payload);
},
+ // normalizes countergroups returns counterGroups and counters.
+ normalizeCounterGroupsHelper: function(parentType, parentID, entity) {
+ // create empty countergroups if not there - to make code below easier.
+ entity.otherinfo.counters = entity.otherinfo.counters || {}
+ entity.otherinfo.counters.counterGroups = entity.otherinfo.counters.counterGroups || [];
+
+ var counterGroups = [];
+ var counters = [];
+
+ var counterGroupsIDs = entity.otherinfo.counters.counterGroups.map(function(counterGroup) {
+ var cg = {
+ id: parentID + '/' + counterGroup.counterGroupName,
+ name: counterGroup.counterGroupName,
+ displayName: counterGroup.counterGroupDisplayName,
+ parentID: { // polymorphic requires type and id.
+ type: parentType,
+ id: parentID
+ }
+ };
+ cg.counters = counterGroup.counters.map(function(counter){
+ var c = {
+ id: cg.id + '/' + counter.counterName,
+ name: counter.counterName,
+ displayName: counter.counterDisplayName,
+ value: counter.counterValue,
+ parentID: cg.id
+ };
+ counters.push(c);
+ return c.id;
+ });
+ counterGroups.push(cg);
+ return cg.id;
+ });
+
+ return {
+ counterGroups: counterGroups,
+ counters: counters,
+ counterGroupsIDs: counterGroupsIDs
+ }
+ }
});
@@ -51,48 +103,43 @@ var timelineJsonToDagMap = {
counterGroups: 'counterGroups'
};
-
App.DagSerializer = App.TimelineSerializer.extend({
- normalizePayload: function(rawPayload){
- // no normalization required for multiple case (findAll)
- if (!!rawPayload.dags) {
- return rawPayload;
- }
-
- var dag = rawPayload.dag;
- var counterGroups = dag.otherinfo.counters.counterGroups;
+ _normalizeSingleDagPayload: function(dag) {
+ var normalizedCounterGroupData = this.normalizeCounterGroupsHelper('dag', dag.entity,
+ dag);
+ dag.counterGroups = normalizedCounterGroupData.counterGroupsIDs;
delete dag.otherinfo.counters;
- // todo move counter parsing outside
- // flatten the dag -> countergroup -> counter structure
- var dagID = dag.entity;
- var allCounters = [];
-
- // put counter group id in the list
- dag['counterGroups'] = counterGroups.map(function(cg) {
- cg.entity = dagID + '/' + cg.counterGroupName;
- cg.parentID = {
- type: 'dag',
- id: dagID
- };
+ return {
+ dag: dag,
+ counterGroups: normalizedCounterGroupData.counterGroups,
+ counters: normalizedCounterGroupData.counters
+ };
+ },
- // replace the counters with thier id.
- cg.counters = cg.counters.map(function(counter){
- counter.entity = cg.entity + '/' + counter.counterName;
- counter.cgID = cg.entity;
- allCounters.push(counter);
- return counter.entity;
- });
+ normalizePayload: function(rawPayload){
- return cg.entity;
- });
+ if (!!rawPayload.dags) {
+ // multiple dags - cames here through _findAll/_findQuery
+ var normalizedPayload = {
+ dags: [],
+ counterGroups: [],
+ counters: []
+ };
+ rawPayload.dags.forEach(function(dag){
+ var n = this._normalizeSingleDagPayload(dag);
+ normalizedPayload.dags.push(n.dag);
+ [].push.apply(normalizedPayload.counterGroups, n.counterGroups);
+ [].push.apply(normalizedPayload.counters, n.counters);
+ }, this);
+
+ // delete so that we dont hang on to the json data.
+ delete rawPayload.dags;
- var normalizedPayload = {
- 'dag': dag,
- 'counterGroups': counterGroups,
- 'counters': allCounters
- };
- return normalizedPayload;
+ return normalizedPayload;
+ } else {
+ return this._normalizeSingleDagPayload(rawPayload.dag);
+ }
},
normalize: function(type, hash, prop) {
@@ -100,58 +147,116 @@ App.DagSerializer = App.TimelineSerializer.extend({
},
});
-App.CounterGroupSerializer = DS.JSONSerializer.extend({
- normalize: function(type, hash, prop) {
- return {
- 'id': hash.entity,
- 'name': hash.counterGroupName,
- 'displayName': hash.counterGroupDisplayName,
- 'counters': hash.counters,
- 'parent': hash.parentID
+var timelineJsonToTaskAttemptMap = {
+ id: 'entity',
+ startTime: 'otherinfo.startTime',
+ endTime: 'otherinfo.endTime',
+ status: 'otherinfo.status',
+ diagnostics: 'otherinfo.diagnostics',
+ counterGroups: 'counterGroups',
+ vertexID: 'primaryfilters.TEZ_VERTEX_ID.0',
+ dagID: 'primaryfilters.TEZ_DAG_ID.0',
+ containerId: { custom: function (source) {
+ var inProgressLogsURL = Em.get(source, 'otherinfo.inProgressLogsURL');
+ var regex = /.*(container_.*?)\/.*/;
+ var match = regex.exec(inProgressLogsURL);
+ return match[1];
+ }}
+};
+
+
+App.TaskAttemptSerializer = App.TimelineSerializer.extend({
+ _normalizeSingleTaskAttemptPayload: function(taskAttempt) {
+ var normalizedCounterGroupData = this.normalizeCounterGroupsHelper('taskAttempt',
+ taskAttempt.entity, taskAttempt);
+ taskAttempt.counterGroups = normalizedCounterGroupData.counterGroupsIDs;
+ delete taskAttempt.otherinfo.counters;
+
+ return {taskAttempt: taskAttempt, counterGroups: normalizedCounterGroupData.counterGroups,
+ counters: normalizedCounterGroupData.counters
};
- }
-});
+ },
+
+ normalizePayload: function(rawPayload){
+
+ if (!!rawPayload.taskAttempts) {
+ var normalizedPayload = {
+ taskAttempts: [],
+ counterGroups: [],
+ counters: []
+ };
+ rawPayload.taskAttempts.forEach(function(taskAttempt){
+ var n = this._normalizeSingleTaskAttemptPayload(taskAttempt);
+ normalizedPayload.taskAttempts.push(n.taskAttempt);
+ [].push.apply(normalizedPayload.counterGroups, n.counterGroups);
+ [].push.apply(normalizedPayload.counters, n.counters);
+ }, this);
+
+ // delete so that we dont hang on to the json data.
+ delete rawPayload.taskAttempts;
+ return normalizedPayload;
+ } else {
+ return this._normalizeSingleTaskAttemptPayload(rawPayload.taskAttempt);
+ }
+ },
-App.CounterSerializer = DS.JSONSerializer.extend({
normalize: function(type, hash, prop) {
- return {
- 'id': hash.entity,
- 'name': hash.counterName,
- 'displayName': hash.counterDisplayName,
- 'value': hash.counterValue,
- 'parent': hash.cgID
- };
- }
+ return Em.JsonMapper.map(hash, timelineJsonToTaskAttemptMap);
+ },
});
-var timelineJsonToTaskAttemptMap = {
+var timelineJsonToTaskMap = {
id: 'entity',
+ dagID: 'primaryfilters.TEZ_DAG_ID.0',
startTime: 'otherinfo.startTime',
+ vertexID: 'primaryfilters.TEZ_VERTEX_ID.0',
endTime: 'otherinfo.endTime',
- dagId: 'primaryfilters.dagId',
- containerId: 'otherinfo.containerId',
status: 'otherinfo.status',
+ diagnostics: 'otherinfo.diagnostics',
+ counterGroups: 'counterGroups',
+ vertexID: 'primaryfilters.TEZ_VERTEX_ID.0',
+ dagID: 'primaryfilters.TEZ_DAG_ID.0',
};
+App.TaskSerializer = App.TimelineSerializer.extend({
+ _normalizeSingleTaskPayload: function(task) {
+ var normalizedCounterGroupData = this.normalizeCounterGroupsHelper('task', task.entity,
+ task);
+ task.counterGroups = normalizedCounterGroupData.counterGroupsIDs;
-App.TaskAttemptSerializer = App.TimelineSerializer.extend({
- normalizePayload: function(rawPayload){
+ delete task.otherinfo.counters;
+
+ return {
+ task: task,
+ counterGroups: normalizedCounterGroupData.counterGroups,
+ counters: normalizedCounterGroupData.counters
+ };
+ },
+
+ normalizePayload: function(rawPayload) {
+ if (!!rawPayload.tasks) {
+ var normalizedPayload = {
+ tasks: [],
+ counterGroups: [],
+ counters: []
+ };
+ rawPayload.tasks.forEach(function(task){
+ var n = this._normalizeSingleTaskPayload(task);
+ normalizedPayload.tasks.push(n.task);
+ [].push.apply(normalizedPayload.counterGroups, n.counterGroups);
+ [].push.apply(normalizedPayload.counters, n.counters);
+ }, this);
+
+ // delete so that we dont hang on to the json data.
+ delete rawPayload.tasks;
- // TODO - fake a containerId until it is present
- var taskAttempts = rawPayload.taskAttempts;
- for (var i = 0; i < taskAttempts.length; ++i) {
- var taskAttempt = taskAttempts[i];
- var inProgressLogsURL = taskAttempt.otherinfo.inProgressLogsURL;
- var regex = /.*(container_.*?)\/.*/;
- var match = regex.exec(inProgressLogsURL);
- taskAttempt.otherinfo.containerId = match[1];
- taskAttempt.primaryfilters.dagId = taskAttempt.primaryfilters.TEZ_DAG_ID[0];
+ return normalizedPayload;
+ } else {
+ return this._normalizeSingleTaskPayload(rawPayload.task);
}
- return rawPayload;
},
normalize: function(type, hash, prop) {
- var post = Em.JsonMapper.map(hash, timelineJsonToTaskAttemptMap);
- return post;
+ return Em.JsonMapper.map(hash, timelineJsonToTaskMap);
},
});
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/models/dag.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/models/dag.js b/tez-ui/app/scripts/models/dag.js
index 7acf984..df4a5c4 100644
--- a/tez-ui/app/scripts/models/dag.js
+++ b/tez-ui/app/scripts/models/dag.js
@@ -203,7 +203,21 @@ App.DagVertex = DS.Model.extend({
}.property('duration')
});
+App.Task = App.AbstractEntity.extend({
+ status: DS.attr('status'),
+ dagID: DS.attr('string'),
+
+ vertexID: DS.attr('string'),
+
+ startTime: DS.attr('number'),
+
+ endTime: DS.attr('number'),
+
+ diagnostics: DS.attr('string'),
+
+ counterGroups: DS.hasMany('counterGroup', { inverse: 'parent' })
+});
App.DagVertexState = {
NEW: "NEW",
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/models/task_attempt.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/models/task_attempt.js b/tez-ui/app/scripts/models/task_attempt.js
index 86cf230..0bc3aec 100644
--- a/tez-ui/app/scripts/models/task_attempt.js
+++ b/tez-ui/app/scripts/models/task_attempt.js
@@ -34,7 +34,9 @@ App.TaskAttempt = App.AbstractEntity.extend({
// status of the task attempt
status: DS.attr('string'),
+ vertexID: DS.attr('string'),
-});
+ dagID: DS.attr('string'),
-App.TaskAttempt.FIXTURES = [];
+ counterGroups: DS.hasMany('counterGroup', { inverse: 'parent' })
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/router.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/router.js b/tez-ui/app/scripts/router.js
index ffac637..a632b7a 100644
--- a/tez-ui/app/scripts/router.js
+++ b/tez-ui/app/scripts/router.js
@@ -19,10 +19,18 @@
App.Router.map(function() {
this.resource('dags', { path: '/' });
this.resource('dag', { path: '/dag/:dag_id'}, function() {
+ this.route('counters'),
this.route('vertex'),
this.route('swimlane')
});
- //this.resource('error', {path: '/error'});
+ this.resource('tasks', {path: '/tasks/:dag_id'});
+ this.resource('task', {path: '/task/:task_id'}, function(){
+ this.route('counters');
+ });
+ this.resource('taskAttempt', {path: '/task_attempt/:task_attempt_id'}, function() {
+ this.route('counters');
+ });
+ //this.resource('error', {path:$ '/error'});
});
/*
@@ -69,6 +77,8 @@ App.DagsRoute = Em.Route.extend({
//TODO remove this
this.store.unloadAll('dag');
+ this.store.unloadAll('counterGroup');
+ this.store.unloadAll('counter');
return this.store.findQuery('dag', queryParams);
},
@@ -100,3 +110,30 @@ App.DagSwimlaneRoute = Em.Route.extend({
this._super(controller, model);
}
});
+
+App.TasksRoute = Em.Route.extend({
+ model: function(params) {
+ var controllerClass = this.controllerFor('tasks');
+ var queryParams = controllerClass.getFilterParams(params);
+
+ //TODO: fix this
+ this.store.unloadAll('task');
+ this.store.unloadAll('counterGroup');
+ this.store.unloadAll('counter');
+ return this.store.findQuery('task', queryParams);
+ },
+
+ setupController: function(controller, model) {
+ this._super(controller, model);
+ }
+});
+
+App.TaskRoute = Em.Route.extend({
+ model: function(params) {
+ return this.store.find('task', params.task_id);
+ },
+
+ setupController: function(controller, model) {
+ this._super(controller, model);
+ }
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/views/show_tasks_view.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/views/show_tasks_view.js b/tez-ui/app/scripts/views/show_tasks_view.js
new file mode 100644
index 0000000..1c196e5
--- /dev/null
+++ b/tez-ui/app/scripts/views/show_tasks_view.js
@@ -0,0 +1,81 @@
+App.ShowTasksView = Em.View.extend({
+ templateName: 'views/show_tasks',
+
+ parentEntityType: '',
+ parentEntityID: '',
+
+ init: function() {
+ this.controller.set('store', this.store);
+ this.controller.set('content', this);
+ },
+
+ columns: function() {
+ var columnHelper = function(columnName, valName) {
+ return Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: columnName,
+ getCellContent: function(row) {
+ return row.get(valName);
+ }
+ });
+ }
+
+ var idColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ //TODO: change hard coding.
+ headerCellName: this.get('parentEntityType') == 'task' ? 'Task Attempt ID' : 'Task Id',
+ tableCellViewClass: Em.Table.TableCell.extend({
+ template: Em.Handlebars.compile(
+ this.get('parentEntityType') == 'task' ?
+ "{{#link-to 'taskAttempt' view.cellContent class='ember-table-content'}}{{view.cellContent}}{{/link-to}}" :
+ "{{#link-to 'task' view.cellContent class='ember-table-content'}}{{view.cellContent}}{{/link-to}}")
+ }),
+ getCellContent: function(row) {
+ return row.get('id');
+ }
+ });
+
+ var vertexColumn = columnHelper('Vertex', 'vertexID');
+
+ var startTimeColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'Submission Time',
+ getCellContent: function(row) {
+ return App.Helpers.date.dateFormat(row.get('startTime'));
+ }
+ });
+
+ var endTimeColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'End Time',
+ getCellContent: function(row) {
+ return App.Helpers.date.dateFormat(row.get('endTime'));
+ }
+ });
+
+ var statusColumn = Em.Table.ColumnDefinition.create({
+ textAlign: 'text-align-left',
+ headerCellName: 'Status',
+ 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>')
+ }),
+ getCellContent: function(row) {
+ return {
+ status: row.get('status'),
+ statusIcon: App.Helpers.misc.getStatusClassForEntity(row)
+ };
+ }
+ });
+
+ //TODO: for now a hack change this to take columns and type to show.
+ if (this.get('parentEntityType') == 'task') {
+ return [idColumn, startTimeColumn, endTimeColumn, statusColumn];
+ } else {
+ return [idColumn, vertexColumn, startTimeColumn, endTimeColumn, statusColumn];
+ }
+ }.property(),
+
+});
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/scripts/views/tasks_view.js
----------------------------------------------------------------------
diff --git a/tez-ui/app/scripts/views/tasks_view.js b/tez-ui/app/scripts/views/tasks_view.js
new file mode 100644
index 0000000..9f1f953
--- /dev/null
+++ b/tez-ui/app/scripts/views/tasks_view.js
@@ -0,0 +1,23 @@
+App.TasksView = Em.View.extend({
+ templateName: 'views/tasks_view',
+
+ init: function() {
+ },
+ parentEntityType: '',
+ parentEntityID: '',
+
+ tasks: [],
+
+ getTasks: function() {
+ return;
+ var store = this.get('controller').get('store');
+ store.findQuery('task', {
+ primaryFilter: 'TEZ_DAG_ID:' + this.get('parentEntityID')
+ }).then(function() {
+ });
+ }.observes('parentEntityID'),
+
+ foo: function() {
+ var x = this.get('parentEntityID');
+ }.on('didInsertElement')
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/styles/main.css
----------------------------------------------------------------------
diff --git a/tez-ui/app/styles/main.css b/tez-ui/app/styles/main.css
deleted file mode 100644
index 67082e9..0000000
--- a/tez-ui/app/styles/main.css
+++ /dev/null
@@ -1,70 +0,0 @@
-
-/* misc helpers */
-.align-right {
- float: right;
-}
-
-.align-left {
- float: left;
-}
-
-.align-clear {
- clear: both;
-}
-
-.margin-small {
- margin: 15px;
-}
-
-.margin-small-horizontal {
- margin: 15px 0px;
-}
-
-.margin-medium {
- margin: 30px;
-}
-
-.type-table {
- display: table;
-}
-
-.fill-full {
- width: 100%;
- height: 100%;
-}
-
-/* Navigation */
-.page-nav-link {
- cursor: pointer;
- color: black;
-}
-
-.page-nav-link.disabled {
- pointer-events: none;
- color:lightgray;
-}
-
-.pill-container {
-
-}
-
-.pill-container {
- display: table-cell;
- margin-right: 30px;
-}
-
-.pill-container a {
- height: 30px !important;
- padding: 5px 15px !important;
-}
-
-/* dag page */
-.detail-list {
- table-layout: fixed;
- overflow: hidden;
- white-space: nowrap;
-}
-
-.detail-list td:first-child {
- width:120px;
-}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/styles/main.less
----------------------------------------------------------------------
diff --git a/tez-ui/app/styles/main.less b/tez-ui/app/styles/main.less
new file mode 100644
index 0000000..570b7c5
--- /dev/null
+++ b/tez-ui/app/styles/main.less
@@ -0,0 +1,133 @@
+@import "../bower_components/font-awesome/less/font-awesome";
+
+.fa-icon(@name) {
+ @content: "fa-var-@{name}";
+ &:before {content: @@content}
+}
+
+/* colors */
+@success-color: limegreen;
+@error-color: crimson;
+@warning-color: orange;
+
+/* misc helpers */
+.align-right {
+ float: right;
+}
+
+.align-left {
+ float: left;
+}
+
+.align-clear {
+ clear: both;
+}
+
+.margin-small {
+ margin: 15px;
+}
+
+.margin-small-horizontal {
+ margin: 15px 0px;
+}
+
+.margin-medium {
+ margin: 30px;
+}
+
+.type-table {
+ display: table;
+}
+
+.fill-full {
+ width: 100%;
+ height: 100%;
+}
+
+/* Navigation */
+.page-nav-link {
+ .fa;
+ //TODO: change this and remove below .fa-3x;
+ font-size: 2.5em;
+ cursor: pointer;
+ color: black;
+
+ &.disabled {
+ pointer-events: none;
+ color:lightgray;
+ }
+
+ &.nav-first {
+ .fa-icon(arrow-circle-o-left);
+ }
+
+ &.nav-prev {
+ .fa-icon(arrow-circle-left)
+ }
+
+ &.nav-next {
+ .fa-icon(arrow-circle-right);
+ }
+}
+
+.pill-container {
+ display: table-cell;
+ margin-right: 30px;
+
+ a {
+ height: 30px !important;
+ padding: 5px 15px !important;
+ }
+}
+
+/* dag page */
+.detail-list {
+ table-layout: fixed;
+ overflow: hidden;
+ white-space: nowrap;
+
+ td {
+ padding: 0px 20px 0px 0px;
+ }
+
+ td:first-child {
+ width:120px;
+ }
+}
+
+/* status related */
+.task-status {
+ .fa;
+ .fa-lg;
+
+ &.success {
+ .fa-icon(check-circle);
+ color: @success-color;
+ }
+
+ &.failure {
+ .fa-icon(exclamation-circle);
+ color: @error-color;
+ }
+
+ &.warning {
+ .fa-icon(exclamation-triangle);
+ color: @warning-color;
+ }
+}
+
+div.indent {
+ margin: 0px 0px 0px 20px;
+ i {
+ .fa;
+ .fa-icon(angle-double-right);
+ }
+}
+
+.countertable-group-header {
+ background-color: lightgray;
+}
+
+.countertable-row {
+ margin: 0px 0px 0px 15px;
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/components/page-nav.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/components/page-nav.hbs b/tez-ui/app/templates/components/page-nav.hbs
index 04cad94..85a254c 100644
--- a/tez-ui/app/templates/components/page-nav.hbs
+++ b/tez-ui/app/templates/components/page-nav.hbs
@@ -16,7 +16,6 @@
* limitations under the License.
}}
-{{!TODO: change to classes. and disable rather than hiding}}
- <i {{bind-attr class=':fa-arrow-circle-o-left :fa :fa-3x :page-nav-link hasPrev:enabled:disabled'}} {{action 'gotoFirst'}}></i>
- <i {{bind-attr class=':fa-arrow-circle-left :fa :fa-3x :page-nav-link hasPrev:enabled:disabled'}} {{action 'gotoPrev'}}></i>
- <i {{bind-attr class=':fa-arrow-circle-right :fa :fa-3x :page-nav-link hasNext:enabled:disabled'}} {{action 'gotoNext'}}></i>
+<i {{bind-attr class=':page-nav-link :nav-first hasPrev:enabled:disabled'}} {{action 'gotoFirst'}}></i>
+<i {{bind-attr class=':page-nav-link :nav-prev hasPrev:enabled:disabled'}} {{action 'gotoPrev'}}></i>
+<i {{bind-attr class=':page-nav-link :nav-next hasNext:enabled:disabled'}} {{action 'gotoNext'}}></i>
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/dag.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/dag.hbs b/tez-ui/app/templates/dag.hbs
index e0ccd05..cd71631 100644
--- a/tez-ui/app/templates/dag.hbs
+++ b/tez-ui/app/templates/dag.hbs
@@ -1,12 +1,15 @@
{{partial "utils/pageHeader"}}
{{#unless loading}}
<div class='margin-small-horizontal'>
- {{#link-to 'dags'}}<i class='fa-arrow-circle-left fa fa-2x'> Dags</i>{{/link-to}}
+ {{#link-to 'dags'}}
+ <i class='fa-arrow-circle-left fa fa-2x'>
+ <span style='font-size: 85%'> Dags</span>
+ </i>
+ {{/link-to}}
</div>
<div class='type-table fill-full margin-small'>
<div class='align-left'>
- {{!simple-kv-list data=this columns=commonDisplayProperties}}
<table class='detail-list'>
<tbody>
@@ -18,6 +21,10 @@
<td>{{t common.applicationId}}</td>
<td>{{applicationId}}</td>
</tr>
+ <tr>
+ <td>{{t common.user}}</td>
+ <td>{{user}}</td>
+ </tr>
</tbody>
</table>
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/dag/counters.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/dag/counters.hbs b/tez-ui/app/templates/dag/counters.hbs
new file mode 100644
index 0000000..ecebc21
--- /dev/null
+++ b/tez-ui/app/templates/dag/counters.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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 margin-medium' style='width: 50%;'>
+ {{counter-table-component data=counterGroups}}
+</div>
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/dag/index.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/dag/index.hbs b/tez-ui/app/templates/dag/index.hbs
index 08610e1..2fe37fc 100644
--- a/tez-ui/app/templates/dag/index.hbs
+++ b/tez-ui/app/templates/dag/index.hbs
@@ -1,41 +1,83 @@
-<table style="table-layout:fixed;overflow:hidden;white-space:nowrap;">
- <thead>
- <tr>
- <th style="width:120px;"></th>
- <th></th>
- </tr>
- </thread>
- <tbody>
- <tr>
- <td>{{t common.status}}</td>
- <td>{{status}}</td>
- </tr>
- <tr>
- <td>{{t common.user}}</td>
- <td>{{user}}</td>
- </tr>
- <tr>
- <td>{{t common.time.start}}</td>
- <td>{{formatUnixTimestamp startTime}}</td>
- </tr>
- <tr>
- <td>{{t common.time.end}}</td>
- <td>{{formatUnixTimestamp endTime}}</td>
- </tr>
- <tr>
- <td>{{t common.time.duration}}</td>
- <td>{{formatDuration startTime endTime}}</td>
- </tr>
- </tbody>
-</table>
+{{!
+* 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.
+}}
-<!-- TODO: merge the groups so that we can collapse - treeview? -->
-<div class="margin-small h4">DAG Counters</div>
-<div class='table-container margin-small'>
- {{table-component
- hasFooter=false
- columnsBinding='counterTableColumns'
- contentBinding='counterContent'
- forceFillColumns=true
- }}
-</div>
\ No newline at end of file
+<div class='type-table fill-full margin-small-horizontal'>
+ <div class='align-left'>
+ <table class='detail-list'>
+ <tbody>
+ <tr>
+ <td>{{t common.status}}</td>
+ <td>
+ {{status}}
+ <i {{bind-attr class=':task-status taskIconStatus'}}></i>
+ </td>
+ </tr>
+ <tr>
+ <td>Total Tasks</td>
+ <td>{{totalTasks}}</td>
+ </tr>
+ <tr>
+ <td>Successful Tasks</td>
+ <td>{{sucessfulTasks}}</td>
+ </tr>
+ <tr>
+ <td>Failed Tasks</td>
+ <td>
+ {{failedTasks}}
+ </td>
+ <td>
+ {{#if hasFailedTasks}}
+ {{!TODO: place link to the tasks that failed}}
+ {{#link-to 'tasks' id}}Failed Tasks{{/link-to}}
+ {{/if}}
+ </td>
+ </tr>
+ <tr>
+ <td>Killed Tasks</td>
+ <td>{{killedTasks}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <div class='align-right'>
+ <table class='detail-list'>
+ <tbody>
+ <tr>
+ <td>{{t common.time.start}}</td>
+ <td>{{formatUnixTimestamp startTime}}</td>
+ </tr>
+ <tr>
+ <td>{{t common.time.end}}</td>
+ <td>{{formatUnixTimestamp endTime}}</td>
+ </tr>
+ <tr>
+ <td>{{t common.time.duration}}</td>
+ <td>{{formatDuration startTime endTime}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+{{#if diagnostics}}
+ {{#bs-panel heading="Diagnostics" collapsible=false dismiss=false type='danger'}}
+ {{formatDiagnostics diagnostics}}
+ {{/bs-panel}}
+{{/if}}
+
+{{view App.ShowTasksView parentEntityType='dag' store=store parentEntityID=content.id controllerBinding='showTasksViewController'}}
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/dag/vertex.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/dag/vertex.hbs b/tez-ui/app/templates/dag/vertex.hbs
index 494a609..decadbc 100644
--- a/tez-ui/app/templates/dag/vertex.hbs
+++ b/tez-ui/app/templates/dag/vertex.hbs
@@ -1 +1 @@
-PlaceHolder for vertex
\ No newline at end of file
+PlaceHolder for tasks
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/dags.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/dags.hbs b/tez-ui/app/templates/dags.hbs
index 86dfca4..647ef42 100644
--- a/tez-ui/app/templates/dags.hbs
+++ b/tez-ui/app/templates/dags.hbs
@@ -21,7 +21,7 @@
{{#unless loading}}
<div class='margin-small'>
<span class='align-left'>
- {{page-nav
+ {{page-nav-component
hasPrev=hasPrev
hasNext=hasNext
navNext='navigateNext'
@@ -43,7 +43,7 @@
<div class='margin-small'>
<span class='align-left'>
- {{page-nav
+ {{page-nav-component
hasPrev=hasPrev
hasNext=hasNext
navNext='navigateNext'
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/task.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/task.hbs b/tez-ui/app/templates/task.hbs
new file mode 100644
index 0000000..112dc92
--- /dev/null
+++ b/tez-ui/app/templates/task.hbs
@@ -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.
+}}
+
+{{partial "utils/pageHeader"}}
+{{#unless loading}}
+ {{!--
+ <div class='margin-small-horizontal'>
+ {{#link-to 'tasks' dagID}}
+ <i class='fa-arrow-circle-left fa fa-2x'>
+ <span style='font-size: 85%'> Tasks</span>
+ </i>
+ {{/link-to}}
+ </div>
+ --}}
+
+ <div class='type-table fill-full '>
+ <div class='align-left'>
+
+ <table class='detail-list'>
+ <tbody>
+ <tr>
+ <td>{{t common.id}}</td>
+ <td>{{id}}</td>
+ </tr>
+ <tr>
+ <td>Vertex ID</td>
+ <td>{{vertexID}}</td>
+ </tr>
+ <tr>
+ <td>DAG ID</td>
+ <td>{{dagID}}</td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+
+ <div class='pill-container align-right'>
+ {{bs-pills contentBinding='childDisplayViews' selectedBinding='childDisplayViewSelected' size='lg'}}
+ </div>
+
+ </div>
+
+ {{outlet}}
+{{else}}
+ {{partial 'utils/loadingSpinner'}}
+{{/unless}}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/task/counters.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/task/counters.hbs b/tez-ui/app/templates/task/counters.hbs
new file mode 100644
index 0000000..4c082e1
--- /dev/null
+++ b/tez-ui/app/templates/task/counters.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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 margin-medium' style='width: 50%;'>
+ {{counter-table-component data=counterGroups}}
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/task/index.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/task/index.hbs b/tez-ui/app/templates/task/index.hbs
new file mode 100644
index 0000000..33da8fd
--- /dev/null
+++ b/tez-ui/app/templates/task/index.hbs
@@ -0,0 +1,59 @@
+{{!
+* 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='type-table fill-full margin-small-horizontal'>
+ <div class='align-left'>
+ <table class='detail-list'>
+ <tbody>
+ <tr>
+ <td>{{t common.status}}</td>
+ <td>
+ {{status}}
+ <i {{bind-attr class=':task-status taskIconStatus'}}></i>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <div class='align-right'>
+ <table class='detail-list'>
+ <tbody>
+ <tr>
+ <td>{{t common.time.start}}</td>
+ <td>{{formatUnixTimestamp startTime}}</td>
+ </tr>
+ <tr>
+ <td>{{t common.time.end}}</td>
+ <td>{{formatUnixTimestamp endTime}}</td>
+ </tr>
+ <tr>
+ <td>{{t common.time.duration}}</td>
+ <td>{{formatDuration startTime endTime}}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+</div>
+
+{{#if diagnostics}}
+ {{#bs-panel heading="Diagnostics" collapsible=false dismiss=false type='danger'}}
+ {{formatDiagnostics diagnostics}}
+ {{/bs-panel}}
+{{/if}}
+
+{{view App.ShowTasksView parentEntityType='task' store=store parentEntityID=content.id controllerBinding='showTasksViewController'}}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/taskAttempt/counters.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/taskAttempt/counters.hbs b/tez-ui/app/templates/taskAttempt/counters.hbs
new file mode 100644
index 0000000..4c082e1
--- /dev/null
+++ b/tez-ui/app/templates/taskAttempt/counters.hbs
@@ -0,0 +1,21 @@
+{{!
+* 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 margin-medium' style='width: 50%;'>
+ {{counter-table-component data=counterGroups}}
+</div>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/task_attempt.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/task_attempt.hbs b/tez-ui/app/templates/task_attempt.hbs
new file mode 100644
index 0000000..d09f28d
--- /dev/null
+++ b/tez-ui/app/templates/task_attempt.hbs
@@ -0,0 +1,51 @@
+{{!
+* 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.
+}}
+
+{{partial "utils/pageHeader"}}
+{{#unless loading}}
+ <div class='type-table fill-full '>
+ <div class='align-left'>
+ <table class='detail-list'>
+ <tbody>
+ <tr>
+ <td>{{t common.id}}</td>
+ <td>{{id}}</td>
+ </tr>
+ <tr>
+ <td>Vertex ID</td>
+ <td>{{vertexID}}</td>
+ </tr>
+ <tr>
+ <td>DAG ID</td>
+ <td>{{dagID}}</td>
+ </tr>
+ </tbody>
+ </table>
+
+ </div>
+
+ <div class='pill-container align-right'>
+ {{bs-pills contentBinding='childDisplayViews' selectedBinding='childDisplayViewSelected' size='lg'}}
+ </div>
+
+ </div>
+
+ {{outlet}}
+{{else}}
+ {{partial 'utils/loadingSpinner'}}
+{{/unless}}
http://git-wip-us.apache.org/repos/asf/tez/blob/f6d85173/tez-ui/app/templates/tasks.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/app/templates/tasks.hbs b/tez-ui/app/templates/tasks.hbs
new file mode 100644
index 0000000..4c84164
--- /dev/null
+++ b/tez-ui/app/templates/tasks.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.
+}}
+
+{{partial 'utils/pageHeader'}}
+
+{{#unless loading}}
+ <div class='margin-small'>
+ <span class='align-left'>
+ {{page-nav-component
+ hasPrev=hasPrev
+ hasNext=hasNext
+ navNext='navigateNext'
+ navPrev='navigatePrev'
+ navFirst='navigateFirst'
+ }}
+ </span>
+ <div class='align-clear'> </div>
+ </div>
+
+ <div class='table-container'>
+ {{table-component
+ hasFooter=false
+ columnsBinding='columns'
+ contentBinding='sortedContent'
+ forceFillColumns=true
+ }}
+ </div>
+
+ <div class='margin-small'>
+ <span class='align-left'>
+ {{page-nav-component
+ hasPrev=hasPrev
+ hasNext=hasNext
+ navNext='navigateNext'
+ navPrev='navigatePrev'
+ navFirst='navigateFirst'
+ }}
+ </span>
+ <div class='align-clear'></div>
+ </div>
+{{else}}
+ {{partial 'utils/loadingSpinner'}}
+{{/unless}}
\ No newline at end of file