You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tez.apache.org by sr...@apache.org on 2016/02/01 11:21:43 UTC

tez git commit: TEZ-3062. Tez UI 2: Integrate graphical view (sree)

Repository: tez
Updated Branches:
  refs/heads/TEZ-2980 231c4d157 -> 480ea0785


TEZ-3062. Tez UI 2: Integrate graphical view (sree)


Project: http://git-wip-us.apache.org/repos/asf/tez/repo
Commit: http://git-wip-us.apache.org/repos/asf/tez/commit/480ea078
Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/480ea078
Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/480ea078

Branch: refs/heads/TEZ-2980
Commit: 480ea0785ac4963b9773ae0df51b92022bf912a3
Parents: 231c4d1
Author: Sreenath Somarajapuram <sr...@apache.org>
Authored: Mon Feb 1 15:49:31 2016 +0530
Committer: Sreenath Somarajapuram <sr...@apache.org>
Committed: Mon Feb 1 15:49:31 2016 +0530

----------------------------------------------------------------------
 TEZ-2980-CHANGES.txt                            |   1 +
 tez-ui2/src/main/webapp/app/controllers/dag.js  |   3 +
 .../webapp/app/controllers/dag/graphical.js     | 165 +++++++++++++++++++
 tez-ui2/src/main/webapp/app/entities/entity.js  |   1 +
 tez-ui2/src/main/webapp/app/models/dag.js       |   5 +
 tez-ui2/src/main/webapp/app/router.js           |   1 +
 .../src/main/webapp/app/routes/dag/graphical.js |  79 +++++++++
 tez-ui2/src/main/webapp/app/routes/pollster.js  |   1 +
 tez-ui2/src/main/webapp/app/serializers/dag.js  |   4 +
 .../main/webapp/app/templates/dag/graphical.hbs |  14 ++
 tez-ui2/src/main/webapp/config/environment.js   |   3 +-
 tez-ui2/src/main/webapp/package.json            |   1 +
 .../unit/controllers/dag/graphical-test.js      |  46 ++++++
 .../tests/unit/routes/dag/graphical-test.js     |  38 +++++
 14 files changed, 361 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/TEZ-2980-CHANGES.txt
----------------------------------------------------------------------
diff --git a/TEZ-2980-CHANGES.txt b/TEZ-2980-CHANGES.txt
index 0457cb0..653899c 100644
--- a/TEZ-2980-CHANGES.txt
+++ b/TEZ-2980-CHANGES.txt
@@ -29,3 +29,4 @@ ALL CHANGES:
   TEZ-3060. Tez UI 2: Activate auto-refresh
   TEZ-3061. Tez UI 2: Display in-progress vertex table in DAG details
   TEZ-3069. Tez UI 2: Make error bar fully functional
+  TEZ-3062. Tez UI 2: Integrate graphical view

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/controllers/dag.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/controllers/dag.js b/tez-ui2/src/main/webapp/app/controllers/dag.js
index 4c8ec1a..2ef4fac 100644
--- a/tez-ui2/src/main/webapp/app/controllers/dag.js
+++ b/tez-ui2/src/main/webapp/app/controllers/dag.js
@@ -38,6 +38,9 @@ export default ParentController.extend({
     text: "DAG Counters",
     routeName: "dag.counters"
   }, {
+    text: "Graphical View",
+    routeName: "dag.graphical"
+  }, {
     text: "All Vertices",
     routeName: "dag.vertices"
   }, {

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/controllers/dag/graphical.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/controllers/dag/graphical.js b/tez-ui2/src/main/webapp/app/controllers/dag/graphical.js
new file mode 100644
index 0000000..a6e42c3
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/controllers/dag/graphical.js
@@ -0,0 +1,165 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+
+import MultiTableController from '../multi-table';
+import ColumnDefinition from 'em-table/utils/column-definition';
+
+export default MultiTableController.extend({
+
+  columnSelectorTitle: 'Customize vertex tooltip',
+
+  breadcrumbs: [{
+    text: "Graphical View",
+    routeName: "dag.graphical",
+  }],
+
+  columns: ColumnDefinition.make([{
+    id: 'name',
+    headerTitle: 'Vertex Name',
+    contentPath: 'name',
+    cellComponentName: 'em-table-linked-cell',
+    getCellContent: function (row) {
+      return {
+        routeName: "vertex",
+        model: row.get("entityID"),
+        text: row.get("name")
+      };
+    }
+  },{
+    id: 'entityID',
+    headerTitle: 'Vertex Id',
+    contentPath: 'entityID'
+  },{
+    id: 'status',
+    headerTitle: 'Status',
+    contentPath: 'status',
+    cellComponentName: 'em-table-status-cell',
+    observePath: true
+  },{
+    id: 'progress',
+    headerTitle: 'Progress',
+    contentPath: 'progress',
+    cellComponentName: 'em-table-progress-cell',
+    observePath: true
+  },{
+    id: 'startTime',
+    headerTitle: 'Start Time',
+    contentPath: 'startTime',
+    cellDefinition: {
+      type: 'date'
+    }
+  },{
+    id: 'endTime',
+    headerTitle: 'End Time',
+    contentPath: 'endTime',
+    cellDefinition: {
+      type: 'date'
+    }
+  },{
+    id: 'duration',
+    headerTitle: 'Duration',
+    contentPath: 'duration',
+    cellDefinition: {
+      type: 'duration'
+    }
+  },{
+    id: 'firstTaskStartTime',
+    headerTitle: 'First Task Start Time',
+    contentPath: 'firstTaskStartTime',
+    cellDefinition: {
+     type: 'date'
+    }
+  },{
+    id: 'totalTasks',
+    headerTitle: 'Tasks',
+    contentPath: 'totalTasks',
+  },{
+    id: 'processorClassName',
+    headerTitle: 'Processor Class',
+    contentPath: 'processorClassName',
+  }]),
+
+  redirect: function (details) {
+    switch(details.type) {
+      case 'vertex':
+        this.transitionToRoute('vertex.index', details.d.get('data.entityID'));
+      break;
+      case 'task':
+        this.transitionToRoute('vertex.tasks', details.d.get('data.entityID'));
+      break;
+      case 'io':
+      break;
+      case 'input':
+      break;
+      case 'output':
+      break;
+    }
+  },
+
+  actions: {
+    entityClicked: function (details) {
+
+      /**
+       * In IE 11 under Windows 7, mouse events are not delivered to the page
+       * anymore at all after a SVG use element that was under the mouse is
+       * removed from the DOM in the event listener in response to a mouse click.
+       * See https://connect.microsoft.com/IE/feedback/details/796745
+       *
+       * This condition and related actions must be removed once the bug is fixed
+       * in all supported IE versions
+       */
+      if(this.get("env.ENV.isIE")) {
+        var pageType = details.type === "io" ? "additionals" : details.type,
+            message = `You will be redirected to ${pageType} page`;
+
+        alert(message);
+      }
+      this.redirect(details);
+    }
+  },
+
+  viewData: Ember.computed("model", function () {
+    var model = this.get("model"),
+        dag, vertices, entities;
+
+    if(!model) {
+      return {};
+    }
+
+    dag = this.get('model.firstObject.dag');
+    vertices = this.get('model.firstObject.dag.vertices') || [];
+    entities = {};
+
+    model.forEach(function (vertexData) {
+      entities[vertexData.get('name')] = vertexData;
+    });
+
+    vertices.forEach(function (vertex) {
+      vertex.data = entities[vertex.vertexName];
+    });
+
+    return {
+      vertices: vertices,
+      edges: dag.get('edges'),
+      vertexGroups: dag.get('vertexGroups')
+    };
+  })
+
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/entities/entity.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/entities/entity.js b/tez-ui2/src/main/webapp/app/entities/entity.js
index 6f98097..f763dcf 100644
--- a/tez-ui2/src/main/webapp/app/entities/entity.js
+++ b/tez-ui2/src/main/webapp/app/entities/entity.js
@@ -100,6 +100,7 @@ var Entity = Ember.Object.extend(NameMixin, {
     needLoader.then(function (model) {
       parentModel.refreshLoadTime();
       parentModel.set(needOptions.name, model);
+      return model;
     });
 
     if(needOptions.silent) {

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/models/dag.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/models/dag.js b/tez-ui2/src/main/webapp/app/models/dag.js
index bb4c5df..4c4cd96 100644
--- a/tez-ui2/src/main/webapp/app/models/dag.js
+++ b/tez-ui2/src/main/webapp/app/models/dag.js
@@ -46,6 +46,11 @@ export default AMTimelineModel.extend({
   submitter: DS.attr("string"),
   contextID: DS.attr("string"),
 
+  // Serialize when required
+  vertices: DS.attr('object'),
+  edges: DS.attr('object'),
+  vertexGroups: DS.attr('object'),
+
   domain: DS.attr("string"),
   containerLogs: DS.attr("object"),
   queue: Ember.computed("app", function () {

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/router.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/router.js b/tez-ui2/src/main/webapp/app/router.js
index 1f54580..eb3afb3 100644
--- a/tez-ui2/src/main/webapp/app/router.js
+++ b/tez-ui2/src/main/webapp/app/router.js
@@ -31,6 +31,7 @@ Router.map(function() {
     this.route('attempts');
     this.route('counters');
     this.route('index', function() {});
+    this.route('graphical');
   });
   this.route('vertex', {path: '/vertex/:vertex_id'}, function() {
     this.route('tasks');

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/routes/dag/graphical.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/dag/graphical.js b/tez-ui2/src/main/webapp/app/routes/dag/graphical.js
new file mode 100644
index 0000000..3d9550f
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/routes/dag/graphical.js
@@ -0,0 +1,79 @@
+/**
+ * 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.
+ */
+
+import Ember from 'ember';
+import MultiAmPollsterRoute from '../multi-am-pollster';
+
+export default MultiAmPollsterRoute.extend({
+  title: "Graphical View",
+
+  loaderNamespace: "dag",
+
+  setupController: function (controller, model) {
+    this._super(controller, model);
+    Ember.run.later(this, "startCrumbBubble");
+  },
+
+  load: function (value, query, options) {
+    return this.get("loader").query('vertex', {
+      dagID: this.modelFor("dag").get("id")
+    }, options);
+  },
+
+  _loadedValueObserver: Ember.observer("loadedValue", function () {
+    var loadedValue = this.get("loadedValue"),
+        records = [];
+
+    loadedValue.forEach(function (record) {
+      records.push(record);
+    });
+
+    this.set("polledRecords", records);
+    Ember.run.later(this, "setViewHeight", 100);
+  }),
+
+  setViewHeight: function () {
+    var container = Ember.$('#graphical-view-component-container'),
+        offset;
+
+    if(container) {
+      offset = container.offset();
+      container.height(
+        Math.max(
+          // 50 pixel is left at the bottom
+          offset ? Ember.$(window).height() - offset.top - 70 : 0,
+          500 // Minimum dag view component container height
+        )
+      );
+    }
+  },
+
+  actions: {
+    didTransition: function () {
+      Ember.$(window).on('resize', this.setViewHeight);
+      this._super();
+      return true;
+    },
+    willTransition: function () {
+      Ember.$(window).off('resize', this.setViewHeight);
+      this._super();
+      return true;
+    },
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/routes/pollster.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/pollster.js b/tez-ui2/src/main/webapp/app/routes/pollster.js
index 7d62c39..9e1e40d 100644
--- a/tez-ui2/src/main/webapp/app/routes/pollster.js
+++ b/tez-ui2/src/main/webapp/app/routes/pollster.js
@@ -22,6 +22,7 @@ import AbstractRoute from './abstract';
 export default AbstractRoute.extend({
   polling: Ember.inject.service("pollster"),
 
+  // Todo - Change name to recordsToPoll
   polledRecords: null,
 
   // Must be implemented by inheriting classes

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/serializers/dag.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/serializers/dag.js b/tez-ui2/src/main/webapp/app/serializers/dag.js
index 9da7bb5..f7d2f21 100644
--- a/tez-ui2/src/main/webapp/app/serializers/dag.js
+++ b/tez-ui2/src/main/webapp/app/serializers/dag.js
@@ -116,6 +116,10 @@ export default TimelineSerializer.extend({
     endTime: getEndTime,
     // duration
 
+    vertices: 'otherinfo.dagPlan.vertices',
+    edges: 'otherinfo.dagPlan.edges',
+    vertexGroups: 'otherinfo.dagPlan.vertexGroups',
+
     // appID
     domain: 'domain',
     // queue

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/app/templates/dag/graphical.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/dag/graphical.hbs b/tez-ui2/src/main/webapp/app/templates/dag/graphical.hbs
new file mode 100644
index 0000000..fcb7e86
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/templates/dag/graphical.hbs
@@ -0,0 +1,14 @@
+{{#if loaded}}
+  <br/>
+  <div id="graphical-view-component-container">
+    {{em-tgraph
+      data=viewData
+      vertexProperties=visibleColumns
+      entityClicked='entityClicked'
+      configure='openColumnSelector'
+    }}
+    <div class="dag-view-legend">Refresh updates only the tooltip values. When sources & sinks are hidden, double click green bubble to toggle visibility locally.</div>
+  </div>
+{{else}}
+  {{partial "loading"}}
+{{/if}}

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/config/environment.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/config/environment.js b/tez-ui2/src/main/webapp/config/environment.js
index b102c8f..e5fc8ac 100644
--- a/tez-ui2/src/main/webapp/config/environment.js
+++ b/tez-ui2/src/main/webapp/config/environment.js
@@ -37,7 +37,8 @@ module.exports = function(environment) {
 
     contentSecurityPolicy: {
       'connect-src': "* 'self'",
-      'style-src': "'self' 'unsafe-inline'"
+      'style-src': "'self' 'unsafe-inline'",
+      'script-src': "'self' 'unsafe-inline'"
     }
   };
 

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/package.json
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/package.json b/tez-ui2/src/main/webapp/package.json
index 9cb055b..e30d5bc 100644
--- a/tez-ui2/src/main/webapp/package.json
+++ b/tez-ui2/src/main/webapp/package.json
@@ -23,6 +23,7 @@
   "devDependencies": {
     "bower": "^1.7.1",
     "broccoli-asset-rev": "^2.2.0",
+    "em-tgraph": "0.0.3",
     "ember-bootstrap": "0.5.1",
     "ember-cli": "1.13.13",
     "ember-cli-app-version": "^1.0.0",

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/tests/unit/controllers/dag/graphical-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/controllers/dag/graphical-test.js b/tez-ui2/src/main/webapp/tests/unit/controllers/dag/graphical-test.js
new file mode 100644
index 0000000..cb9ab66
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/unit/controllers/dag/graphical-test.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.
+ */
+
+import Ember from 'ember';
+
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('controller:dag/graphical', 'Unit | Controller | dag/graphical', {
+  // Specify the other units that are required for this test.
+  // needs: ['controller:foo']
+});
+
+test('Basic creation test', function(assert) {
+  let controller = this.subject({
+    send: Ember.K,
+    initVisibleColumns: Ember.K,
+    getCounterColumns: function () {
+      return [];
+    }
+  });
+
+  assert.ok(controller);
+
+  assert.ok(controller.columnSelectorTitle);
+  assert.ok(controller.breadcrumbs);
+  assert.ok(controller.columns);
+
+  assert.ok(controller.redirect);
+  assert.ok(controller.actions.entityClicked);
+  assert.ok(controller.viewData);
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/480ea078/tez-ui2/src/main/webapp/tests/unit/routes/dag/graphical-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/routes/dag/graphical-test.js b/tez-ui2/src/main/webapp/tests/unit/routes/dag/graphical-test.js
new file mode 100644
index 0000000..ab838c5
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/unit/routes/dag/graphical-test.js
@@ -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.
+ */
+
+import { moduleFor, test } from 'ember-qunit';
+
+moduleFor('route:dag/graphical', 'Unit | Route | dag/graphical', {
+  // Specify the other units that are required for this test.
+  // needs: ['controller:foo']
+});
+
+test('Basic creation test', function(assert) {
+  let route = this.subject();
+
+  assert.ok(route);
+  assert.ok(route.title);
+  assert.ok(route.loaderNamespace);
+  assert.ok(route.setupController);
+  assert.ok(route.load);
+  assert.ok(route._loadedValueObserver);
+  assert.ok(route.setViewHeight);
+  assert.ok(route.actions.didTransition);
+  assert.ok(route.actions.willTransition);
+});