tez-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject [2/2] tez git commit: TEZ-3172. Tez UI: Swimlane - In progress & Shadow (sree)
Date Tue, 05 Apr 2016 08:52:27 GMT
TEZ-3172. Tez UI: Swimlane - In progress & Shadow (sree)


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

Branch: refs/heads/master
Commit: 8e9e5ae7fe14c262ebcff5f2364fc5b5275c776a
Parents: 0c7e1c5
Author: Sreenath Somarajapuram <sree@apache.org>
Authored: Tue Apr 5 14:21:54 2016 +0530
Committer: Sreenath Somarajapuram <sree@apache.org>
Committed: Tue Apr 5 14:21:54 2016 +0530

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 .../components/em-swimlane-blocking-event.js    |  31 ++--
 .../em-swimlane-consolidated-process.js         |  89 ++++++++++
 .../app/components/em-swimlane-event-bar.js     |  27 +--
 .../webapp/app/components/em-swimlane-event.js  |   6 +-
 .../app/components/em-swimlane-process-line.js  |  14 +-
 .../components/em-swimlane-process-visual.js    |  74 ++------
 .../webapp/app/components/em-swimlane-ruler.js  |  98 ++++++++++
 .../app/components/em-swimlane-vertex-name.js   |  68 +++++++
 .../main/webapp/app/components/em-swimlane.js   |  82 ++++++---
 .../app/components/em-table-status-cell.js      |  43 +----
 .../main/webapp/app/components/em-tooltip.js    |  33 ++--
 .../webapp/app/controllers/dag/graphical.js     |   2 +-
 .../main/webapp/app/controllers/dag/swimlane.js |  16 +-
 .../main/webapp/app/controllers/dag/vertices.js |   2 +-
 tez-ui2/src/main/webapp/app/models/vertex-am.js |   6 +
 tez-ui2/src/main/webapp/app/models/vertex.js    |  32 +++-
 .../src/main/webapp/app/routes/dag/swimlane.js  |  16 +-
 .../main/webapp/app/serializers/vertex-am.js    |   6 +
 .../src/main/webapp/app/serializers/vertex.js   |   7 +-
 tez-ui2/src/main/webapp/app/styles/app.less     |  10 ++
 .../main/webapp/app/styles/column-selector.less |   3 -
 .../main/webapp/app/styles/details-page.less    |   2 -
 .../app/styles/em-swimlane-vertex-name.less     |  65 +++++++
 .../src/main/webapp/app/styles/em-swimlane.less | 110 +++++++++++-
 .../webapp/app/styles/em-table-status-cell.less |  99 +++++++++++
 .../src/main/webapp/app/styles/em-tooltip.less  |   2 +
 .../src/main/webapp/app/styles/page-layout.less |   3 -
 tez-ui2/src/main/webapp/app/styles/shared.less  |   2 -
 .../main/webapp/app/styles/swimlane-page.less   |   3 +
 .../main/webapp/app/styles/tab-n-refresh.less   |   2 -
 .../main/webapp/app/styles/table-controls.less  |   2 -
 .../em-swimlane-consolidated-process.hbs        |  19 ++
 .../components/em-swimlane-process-visual.hbs   |  13 +-
 .../templates/components/em-swimlane-ruler.hbs  |  30 ++++
 .../components/em-swimlane-vertex-name.hbs      |  23 +++
 .../app/templates/components/em-swimlane.hbs    |  33 +++-
 .../components/em-table-status-cell.hbs         |   5 +-
 .../main/webapp/app/templates/dag/swimlane.hbs  |   5 +-
 .../main/webapp/app/templates/vertex/index.hbs  |   2 +-
 tez-ui2/src/main/webapp/app/utils/process.js    |  16 +-
 tez-ui2/src/main/webapp/app/utils/processor.js  |  50 ++++++
 .../src/main/webapp/app/utils/vertex-process.js | 178 +++++++++++++------
 .../em-swimlane-blocking-event-test.js          |  75 ++++++--
 .../em-swimlane-consolidated-process-test.js    |  61 +++++++
 .../components/em-swimlane-event-bar-test.js    |   6 +-
 .../components/em-swimlane-event-test.js        |  14 +-
 .../components/em-swimlane-process-line-test.js |  31 ++--
 .../em-swimlane-process-visual-test.js          |  12 +-
 .../components/em-swimlane-ruler-test.js        |  70 ++++++++
 .../components/em-swimlane-vertex-name-test.js  |  79 ++++++++
 .../components/em-table-status-cell-test.js     |  15 +-
 .../tests/unit/controllers/dag/swimlane-test.js |   7 +-
 .../webapp/tests/unit/models/vertex-am-test.js  |   7 +
 .../webapp/tests/unit/models/vertex-test.js     |   8 +
 .../webapp/tests/unit/utils/process-test.js     |  17 ++
 .../webapp/tests/unit/utils/processor-test.js   |  68 +++++++
 .../tests/unit/utils/vertex-process-test.js     |  94 +++++++---
 58 files changed, 1529 insertions(+), 365 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 3272638..d64388e 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1898,6 +1898,7 @@ ALL CHANGES
   TEZ-3170. Tez UI 2: Swimlane - Display computed events, event bars & dependencies (sree)
   TEZ-3152. Tez UI 2: Build fails when run by multiple users or when node_modules is old (sree)
   TEZ-3171. Tez UI 2: Swimlane - Tooltip, zoom & redirection (sree)
+  TEZ-3172. Tez UI: Swimlane - In progress & Shadow (sree)
 
 Release 0.2.0-incubating: 2013-11-30
 

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js
index c40bec9..1743540 100644
--- a/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-blocking-event.js
@@ -22,12 +22,14 @@ export default Ember.Component.extend({
 
   process: null,
   blocking: null,
-  events: null,
+
+  processor: null,
 
   classNames: ["em-swimlane-blocking-event"],
 
-  blockingEvent: Ember.computed("events.length", "process.blockingEventName", function () {
-    var events = this.get("events"),
+  blockingEvent: Ember.computed("process.blockingEventName",
+      "process.events.@each.name", function () {
+    var events = this.get("process.events"),
         blockingEventName = this.get("process.blockingEventName");
 
     return events.find(function (event) {
@@ -35,16 +37,21 @@ export default Ember.Component.extend({
     });
   }),
 
-  didInsertElement: Ember.observer("blockingEvent", function () {
-    var blockerEventHeight = (this.get("blocking.index") - this.get("process.index")) * 30;
+  didInsertElement: Ember.observer("blockingEvent.time", "processor.timeWindow", function () {
+    var blockTime = this.get("blockingEvent.time"),
+        blockerEventHeight;
 
-    this.$().css({
-      "left": this.get("blockingEvent.pos") + "%"
-    });
-    this.$(".event-line").css({
-      "height": `${blockerEventHeight}px`,
-      "border-color": this.get("process").getColor()
-    });
+    if(blockTime && this.get("blocking.endEvent.time") >= blockTime) {
+      blockerEventHeight = (this.get("blocking.index") - this.get("process.index")) * 30;
+
+      this.$().css({
+        "left": this.get("processor").timeToPositionPercent(blockTime) + "%"
+      });
+      this.$(".event-line").css({
+        "height": `${blockerEventHeight}px`,
+        "border-color": this.get("process").getColor()
+      });
+    }
   }),
 
   sendMouseAction: function (name, mouseEvent) {

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane-consolidated-process.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-consolidated-process.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-consolidated-process.js
new file mode 100644
index 0000000..67186dd
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-consolidated-process.js
@@ -0,0 +1,89 @@
+/**
+ * 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';
+
+export default Ember.Component.extend({
+
+  process: null,
+  processor: null,
+  focusedProcess: null,
+
+  classNames: ["em-swimlane-consolidated-process"],
+  classNameBindings: ['focused'],
+
+  focused: Ember.computed("process", "focusedProcess", function () {
+    return this.get("process") === this.get("focusedProcess");
+  }),
+
+  fromPos: Ember.computed("process.consolidateStartTime", "processor.timeWindow", function () {
+    var time = this.get("process.consolidateStartTime");
+    if(time) {
+      return this.get("processor").timeToPositionPercent(time);
+    }
+  }),
+
+  toPos: Ember.computed("process.consolidateEndTime", "processor.timeWindow", function () {
+    var time = this.get("process.consolidateEndTime");
+    if(time) {
+      return this.get("processor").timeToPositionPercent(time);
+    }
+  }),
+
+  didInsertElement: Ember.observer("fromPos", "toPos", function () {
+    var fromPos = this.get("fromPos"),
+        toPos = this.get("toPos"),
+        thisElement = this.$();
+
+    if(fromPos && toPos) {
+      thisElement.show();
+      thisElement.css({
+        left: fromPos + "%",
+        right: (100 - toPos) + "%",
+        "background-color": this.get("process").getConsolidateColor(),
+        "z-index": parseInt(toPos - fromPos)
+      });
+    }
+    else {
+      thisElement.hide();
+    }
+  }),
+
+  sendMouseAction: function (name, mouseEvent) {
+    var fromPos = this.get("fromPos") || 0,
+        toPos = this.get("toPos") || 0;
+
+    this.sendAction(name, "consolidated-process", this.get("process"), {
+      mouseEvent: mouseEvent,
+      contribution: parseInt(toPos - fromPos)
+    });
+  },
+
+  mouseEnter: function (mouseEvent) {
+    this.sendMouseAction("showTooltip", mouseEvent);
+  },
+
+  mouseLeave: function (mouseEvent) {
+    this.sendMouseAction("hideTooltip", mouseEvent);
+  },
+
+  mouseUp: function (mouseEvent) {
+    this.sendMouseAction("click", mouseEvent);
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js
index 7afb312..11be2ff 100644
--- a/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-event-bar.js
@@ -20,35 +20,36 @@ import Ember from 'ember';
 
 export default Ember.Component.extend({
 
-  process: null,
-  events: [],
-
-  bars: [],
   bar: null,
   barIndex: 0,
 
+  process: null,
+  processor: null,
+
   classNames: ["em-swimlane-event-bar"],
 
-  fromEvent: Ember.computed("events.length", "bar.fromEvent", function () {
-    var events = this.get("events"),
+  fromEvent: Ember.computed("process.events.@each.name", "bar.fromEvent", function () {
+    var events = this.get("process.events"),
         fromEventName = this.get("bar.fromEvent");
     return events.find(function (event) {
       return event.name === fromEventName;
     });
   }),
-  toEvent: Ember.computed("events.length", "bar.toEvent", function () {
-    var events = this.get("events"),
+  toEvent: Ember.computed("process.events.@each.name", "bar.toEvent", function () {
+    var events = this.get("process.events"),
         toEventName = this.get("bar.toEvent");
     return events.find(function (event) {
       return event.name === toEventName;
     });
   }),
 
-  didInsertElement: Ember.observer("fromEvent.pos", "toEvent.pos", "barIndex", function () {
-    var fromEventPos = this.get("fromEvent.pos"),
-        toEventPos = this.get("toEvent.pos"),
-        color = this.get("bar.color") ||
-            this.get("process").getColor(1 - (this.get("barIndex") / this.get("bars.length")));
+  didInsertElement: Ember.observer("fromEvent.time", "toEvent.time",
+      "barIndex", "processor.timeWindow", function () {
+
+    var processor = this.get("processor"),
+        fromEventPos = processor.timeToPositionPercent(this.get("fromEvent.time")),
+        toEventPos = processor.timeToPositionPercent(this.get("toEvent.time")),
+        color = this.get("bar.color") || this.get("process").getBarColor(this.get("barIndex"));
 
     if(fromEventPos && toEventPos) {
       this.$().show();

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js
index c4d31ca..20dc943 100644
--- a/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-event.js
@@ -23,13 +23,15 @@ export default Ember.Component.extend({
   process: null,
   event: null,
 
+  processor: null,
+
   classNames: ["em-swimlane-event"],
 
-  didInsertElement: Ember.observer("event.pos", function () {
+  didInsertElement: Ember.observer("event.time", "processor.timeWindow", function () {
     var color = this.get("process").getColor();
 
     this.$().css({
-      "left": this.get("event.pos") + "%"
+      "left": this.get("processor").timeToPositionPercent(this.get("event.time")) + "%"
     });
     this.$(".event-line").css("border-color", color);
     this.$(".event-bubble").css("border-color", color);

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane-process-line.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-process-line.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-process-line.js
index ab4972b..2309004 100644
--- a/tez-ui2/src/main/webapp/app/components/em-swimlane-process-line.js
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-process-line.js
@@ -21,13 +21,17 @@ import Ember from 'ember';
 export default Ember.Component.extend({
 
   process: null,
-  startEvent: null,
-  endEvent: null,
+  processor: null,
+
+  didInsertElement: Ember.observer("process.startEvent.time",
+      "process.endEvent.time", "processor.timeWindow", function () {
+    var processor = this.get("processor"),
+        startPos = processor.timeToPositionPercent(this.get("process.startEvent.time")),
+        endPos = processor.timeToPositionPercent(this.get("process.endEvent.time"));
 
-  didInsertElement: Ember.observer("startEvent.pos", "endEvent.pos", function () {
     this.$(".process-line").css({
-      left: this.get("startEvent.pos") + "%",
-      right: (100 - this.get("endEvent.pos")) + "%",
+      left: startPos + "%",
+      right: (100 - endPos) + "%",
       "background-color": this.get("process").getColor()
     });
   }),

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js
index caa7603..aa555cd 100644
--- a/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-process-visual.js
@@ -18,87 +18,43 @@
 
 import Ember from 'ember';
 
-const BUBBLE_RADIUS = 8; // Same as that in css
+const BUBBLE_DIA = 10; // Same as that in css
 
 export default Ember.Component.extend({
-  process: null,
-  definition: null,
-
-  startTime: 0,
-  endTime: 0,
-  timeWindow: 0,
 
-  normalizedEvents: [],
-  startEvent: null,
-  endEvent: null,
+  process: null,
+  processor: null,
+  focusedProcess: null,
 
-  eventBars: [],
   classNames: ["em-swimlane-process-visual"],
 
-  didInsertElement: function () {
-    Ember.run.later(this, "normalizeEvents");
-  },
-
-  normalizeEvents: Ember.observer("process.events.@each.time", "startTime", "timeWindow", function () {
-    var events = Ember.get(this.get("process"), "events") || [],
-        startEvent,
-        endEvent,
-
-        startTime = this.get("startTime"),
-        timeWindow = this.get("timeWindow");
-
-    events = events.map(function (event) {
-      var position = ((event.time - startTime) / timeWindow) * 100;
-      event = {
-        name: event.name,
-        text: event.text || event.name,
-        pos: position,
-        time: event.time
-      };
-
-      if(!startEvent || startEvent.pos > position) {
-        startEvent = event;
-      }
-      if(!endEvent || endEvent.pos < position) {
-        endEvent = event;
-      }
-
-      return event;
-    });
-
-    this.setProperties({
-      normalizedEvents: events,
-      startEvent: startEvent,
-      endEvent: endEvent
-    });
-  }),
-
   actions: {
     showTooltip: function(type, process, options) {
 
       if(type === "event") {
-        let mouseEvent = options.mouseEvent,
-            normalizedEvents = this.get("normalizedEvents"),
-            events = [];
+        let clientX = options.mouseEvent.clientX,
+            events = process.get("events"),
+            eventsUnderMouse = [];
 
         this.$(".em-swimlane-event").each(function (index) {
-          var offset = Ember.$(this).offset();
+          var offsetLeft = Ember.$(this).offset().left;
 
-          if(mouseEvent.clientX >= offset.left - BUBBLE_RADIUS &&
-              mouseEvent.clientX <= offset.left + BUBBLE_RADIUS &&
-              mouseEvent.clientY >= offset.top - BUBBLE_RADIUS &&
-              mouseEvent.clientY <= offset.top + BUBBLE_RADIUS) {
-            events.push(normalizedEvents[index]);
+          if(clientX >= offsetLeft - BUBBLE_DIA && clientX <= offsetLeft + BUBBLE_DIA) {
+            eventsUnderMouse.push(events[index]);
           }
         });
 
         if(events.length) {
-          options.events = events;
+          eventsUnderMouse.sort(function (eventA, eventB) {
+            return eventA.time - eventB.time;
+          });
+          options.events = eventsUnderMouse;
         }
       }
 
       this.sendAction("showTooltip", type, process, options);
     },
+
     hideTooltip: function(type, process, options) {
       this.sendAction("hideTooltip", type, process, options);
     },

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane-ruler.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-ruler.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-ruler.js
new file mode 100644
index 0000000..4d1b933
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-ruler.js
@@ -0,0 +1,98 @@
+/**
+ * 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 moment from 'moment';
+
+const DEFAULT_MARK_COUNT = 10;
+
+export default Ember.Component.extend({
+
+  zoom: null,
+  processor: null,
+  scroll: 0,
+
+  classNames: ["em-swimlane-ruler"],
+
+  markDef: Ember.computed("processor.timeWindow", "zoom", function () {
+    var markCount = parseInt(DEFAULT_MARK_COUNT * this.get("zoom") / 100),
+        timeWindow = this.get("processor.timeWindow"),
+        duration = moment.duration(parseInt(timeWindow / markCount)),
+
+        markUnit = "Milliseconds",
+        markBaseValue = 0,
+        markWindow = 0,
+        styleWidth = 0;
+
+    if(markBaseValue = duration.years()) {
+      markUnit = "Years";
+    }
+    else if(markBaseValue = duration.months()) {
+      markUnit = "Months";
+    }
+    else if(markBaseValue = duration.days()) {
+      markUnit = "Days";
+    }
+    else if(markBaseValue = duration.hours()) {
+      markUnit = "Hours";
+    }
+    else if(markBaseValue = duration.minutes()) {
+      markUnit = "Minutes";
+    }
+    else if(markBaseValue = duration.seconds()) {
+      markUnit = "Seconds";
+    }
+    else {
+      markBaseValue = duration.milliseconds();
+    }
+
+    if(markBaseValue > 10) {
+      markBaseValue = Math.floor(markBaseValue / 10) * 10;
+    }
+
+    markWindow = moment.duration(markBaseValue, markUnit.toLowerCase()).asMilliseconds();
+    styleWidth = markWindow / timeWindow * 100;
+
+    return {
+      unit: markUnit,
+      baseValue: markBaseValue,
+      style: Ember.String.htmlSafe(`width: ${styleWidth}%;`),
+      count: parseInt(100 / styleWidth * 1.1)
+    };
+  }),
+
+  unitTextStyle: Ember.computed("scroll", function () {
+    var scroll = this.get("scroll");
+    return Ember.String.htmlSafe(`left: ${scroll}px;`);
+  }),
+
+  marks: Ember.computed("processor.timeWindow", "markDef", function () {
+    var def = this.get("markDef"),
+        baseValue = def.baseValue,
+        marks = [];
+
+    for(var i=0, count = def.count; i < count; i++) {
+      marks.push({
+        duration: parseInt(baseValue * i)
+      });
+    }
+
+    return marks;
+  })
+
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane-vertex-name.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane-vertex-name.js b/tez-ui2/src/main/webapp/app/components/em-swimlane-vertex-name.js
new file mode 100644
index 0000000..136125a
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane-vertex-name.js
@@ -0,0 +1,68 @@
+/**
+ * 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';
+
+const MAX_TEXT_LENGTH = 10;
+
+export default Ember.Component.extend({
+
+  process: null,
+
+  classNames: ["em-swimlane-vertex-name"],
+
+  sendMouseAction: function (name, mouseEvent) {
+    this.sendAction(name, "process-name", this.get("process"), {
+      mouseEvent: mouseEvent,
+    });
+  },
+
+  progressText: Ember.computed("process.vertex.progress", function () {
+    var percent = parseInt(this.get("process.vertex.progress") * 100);
+    if(!isNaN(percent) && percent > 0 && percent < 100) {
+      return `${percent}%`;
+    }
+  }),
+
+  useEllipsis: Ember.computed("process.name", "progressText", function () {
+    var name = this.get("process.name") || "",
+        progressLength = this.get("progressText.length");
+    progressLength = progressLength ? progressLength + 1 : 0;
+    return  name.length + progressLength - 1 > MAX_TEXT_LENGTH;
+  }),
+
+  processName: Ember.computed("process.name", "progressText", function () {
+    var name = this.get("process.name") || "",
+        progressLength = this.get("progressText.length");
+    progressLength = progressLength ? progressLength + 1 : 0;
+    return name.substr(Math.max(name.length - MAX_TEXT_LENGTH - progressLength, 0));
+  }),
+
+  mouseEnter: function (mouseEvent) {
+    this.sendMouseAction("showTooltip", mouseEvent);
+  },
+
+  mouseLeave: function (mouseEvent) {
+    this.sendMouseAction("hideTooltip", mouseEvent);
+  },
+
+  mouseUp: function (mouseEvent) {
+    this.sendMouseAction("click", mouseEvent);
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-swimlane.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-swimlane.js b/tez-ui2/src/main/webapp/app/components/em-swimlane.js
index c05461f..0c8b589 100644
--- a/tez-ui2/src/main/webapp/app/components/em-swimlane.js
+++ b/tez-ui2/src/main/webapp/app/components/em-swimlane.js
@@ -18,51 +18,83 @@
 
 import Ember from 'ember';
 
-import ProcessDefinition from '../utils/process-definition';
+import Processor from '../utils/processor';
 import Process from '../utils/process';
 
-function getVibrantHSL(colorNum, totalColors) {
-  if (totalColors < 1){
-    totalColors = 1;
-  }
-  return {
-    h: colorNum * (360 / totalColors) % 360,
-    s: 100 - (colorNum % 2) * 30,
-    l: 40
-  };
-}
-
 export default Ember.Component.extend({
 
   classNames: ["em-swimlane"],
 
   processes: [],
-  processDefinition: ProcessDefinition.create(),
-
-  startTime: null,
-  endTime: null,
+  processor: Processor.create(),
 
-  eventBars: [],
+  nameComponent: "em-swimlane-process-name",
+  visualComponent: "em-swimlane-process-visual",
 
   tooltipContents: null,
+  focusedProcess: null,
+  scroll: 0,
+
+  consolidate: false,
 
   zoom: 100,
 
-  didInsertElement: Ember.observer("zoom", function () {
+  startTime: Ember.computed("processes.@each.startEvent", function () {
+    var startTime = this.get("processes.0.startEvent.time");
+    this.get("processes").forEach(function (process) {
+      var time = process.get("startEvent.time");
+      if(startTime > time){
+        startTime = time;
+      }
+    });
+    return startTime;
+  }),
+  endTime: Ember.computed("processes.@each.endEvent", function () {
+    var endTime = this.get("processes.0.endEvent.time");
+    this.get("processes").forEach(function (process) {
+      var time = process.get("endEvent.time");
+      if(endTime < time){
+        endTime = time;
+      }
+    });
+    return endTime;
+  }),
+
+  processorSetup: Ember.on("init", Ember.observer("startTime", "endTime", "processes.length", function () {
+    this.get("processor").setProperties({
+      startTime: this.get("startTime"),
+      endTime: this.get("endTime"),
+      processCount: this.get("processes.length")
+    });
+  })),
+
+  didInsertElement: function () {
+    this.onZoom();
+    this.listenScroll();
+  },
+
+  onZoom: Ember.observer("zoom", function () {
     var zoom = this.get("zoom");
     this.$(".zoom-panel").css("width", `${zoom}%`);
   }),
 
-  timeWindow: Ember.computed("startTime", "endTime", function () {
-    return Math.max(0, this.get("endTime") - this.get("startTime"));
-  }),
+  listenScroll: function () {
+    var that = this;
+    this.$(".process-visuals").scroll(function () {
+      that.set("scroll", Ember.$(this).scrollLeft());
+    });
+  },
+
+  willDestroy: function () {
+    // Release listeners
+  },
 
   normalizedProcesses: Ember.computed("processes.@each.blockers", function () {
     var processes = this.get("processes"),
-        processCount = processes.length,
         normalizedProcesses,
         idHash = {},
-        containsBlockers = false;
+        containsBlockers = false,
+        processor = this.get("processor");
 
     // Validate and reset blocking
     processes.forEach(function (process) {
@@ -114,7 +146,7 @@ export default Ember.Component.extend({
     // Set process colors & index
     normalizedProcesses.forEach(function (process, index) {
       process.setProperties({
-        color: getVibrantHSL(index, processCount),
+        color: processor.createProcessColor(index),
         index: index
       });
     });
@@ -125,9 +157,11 @@ export default Ember.Component.extend({
   actions: {
     showTooltip: function (type, process, options) {
       this.set("tooltipContents", process.getTooltipContents(type, options));
+      this.set("focusedProcess", process);
     },
     hideTooltip: function () {
       this.set("tooltipContents", null);
+      this.set("focusedProcess", null);
     },
     click: function (type, process, options) {
       this.sendAction("click", type, process, options);

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-table-status-cell.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-table-status-cell.js b/tez-ui2/src/main/webapp/app/components/em-table-status-cell.js
index bfa74e1..7751719 100644
--- a/tez-ui2/src/main/webapp/app/components/em-table-status-cell.js
+++ b/tez-ui2/src/main/webapp/app/components/em-table-status-cell.js
@@ -22,42 +22,15 @@ export default Ember.Component.extend({
 
   content: null,
 
-  statusTypes: {
-    // Basic types
-    "default": "default",
-    "primary": "primary",
-    "success": "success",
-    "info": "info",
-    "warning": "warning",
-    "danger": "danger",
+  classNames: ["em-table-status-cell"],
 
-    // Extended types
-    "new": "default",
-    "inited": "primary",
-    "initializing": "primary",
-    "scheduled": "primary",
-    "start_wait": "primary",
-    "running": "info",
-    "succeeded": "success",
-    "failed": "warning",
-    "fail_in_progress": "warning",
-    "killed": "danger",
-    "kill_wait": "warning",
-    "kill_in_progress": "warning",
-    "error": "danger",
-    "terminating": "warning",
-    "committing": "info",
-  },
+  statusName: Ember.computed("content", function () {
+    var status = this.get("content");
 
-  statusType: Ember.computed("content", function () {
-    var content = this.get("content"),
-        statusType;
-
-    if(content) {
-      content = content.toString().toLowerCase();
-      statusType = this.get(`statusTypes.${content}`) || 'default';
+    if(status) {
+      status = status.toString().dasherize();
+      status = "status-" + status;
     }
-
-    return statusType;
-  })
+    return status;
+  }),
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/components/em-tooltip.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/em-tooltip.js b/tez-ui2/src/main/webapp/app/components/em-tooltip.js
index 093ca3d..33e30cb 100644
--- a/tez-ui2/src/main/webapp/app/components/em-tooltip.js
+++ b/tez-ui2/src/main/webapp/app/components/em-tooltip.js
@@ -18,7 +18,7 @@
 
 import Ember from 'ember';
 
-const TIP_PADDING = 10, // As in em-tooltip.css
+const TIP_PADDING = 15, // As in em-tooltip.css
       FADE_TIME = 150;
 
 export default Ember.Component.extend({
@@ -29,14 +29,14 @@ export default Ember.Component.extend({
   contents: null,
 
   classNames: ["em-tooltip"],
-  classNameBindings: ["aboveOrBelow"],
+  classNameBindings: ["arrowPos"],
 
   x: 0,
   y: 0,
 
   _contents: null,
   show: false,
-  aboveOrBelow: null,
+  arrowPos: null,
 
   window: null,
   tip: null,
@@ -99,18 +99,14 @@ export default Ember.Component.extend({
   },
 
   getBubbleOffset: function (x, bubbleElement, winWidth) {
-    var bubbleWidth = bubbleElement.width(),
-        bubbleOffset = (bubbleWidth - TIP_PADDING) >> 1;
+    var bubbleWidth = Math.max(bubbleElement.width(), 0),
+        bubbleOffset = bubbleWidth >> 1;
 
-    if(bubbleWidth < 0) {
-      bubbleWidth = 0;
-    }
-
-    if(x - bubbleOffset < 0) {
-      bubbleOffset = x;
+    if(x - bubbleOffset - TIP_PADDING < 0) {
+      bubbleOffset = x - TIP_PADDING;
     }
     else if(x + TIP_PADDING + bubbleOffset > winWidth) {
-      bubbleOffset = x - (winWidth - bubbleWidth);
+      bubbleOffset = x - (winWidth - bubbleWidth) + TIP_PADDING;
     }
 
     return -bubbleOffset;
@@ -129,12 +125,17 @@ export default Ember.Component.extend({
           that = this,
           tip = this.get("tip");
 
-      if(!showAbove) {
-        y -= tip.height();
-        this.set("aboveOrBelow", "below");
+      if(x > TIP_PADDING && x < winWidth - TIP_PADDING) {
+        if(!showAbove) {
+          y -= tip.height();
+          this.set("arrowPos", "below");
+        }
+        else {
+          this.set("arrowPos", "above");
+        }
       }
       else {
-        this.set("aboveOrBelow", "above");
+        this.set("arrowPos", null);
       }
 
       tip.css({

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/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
index 470628c..535f32b 100644
--- a/tez-ui2/src/main/webapp/app/controllers/dag/graphical.js
+++ b/tez-ui2/src/main/webapp/app/controllers/dag/graphical.js
@@ -49,7 +49,7 @@ export default MultiTableController.extend({
   },{
     id: 'status',
     headerTitle: 'Status',
-    contentPath: 'status',
+    contentPath: 'finalStatus',
     cellComponentName: 'em-table-status-cell',
     observePath: true
   },{

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js b/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js
index cf69e1f..466f080 100644
--- a/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js
+++ b/tez-ui2/src/main/webapp/app/controllers/dag/swimlane.js
@@ -28,6 +28,8 @@ export default MultiTableController.extend({
 
   zoom: 100,
 
+  columnSelectorTitle: 'Customize vertex tooltip',
+
   breadcrumbs: [{
     text: "Vertex Swimlane",
     routeName: "dag.swimlane",
@@ -40,7 +42,7 @@ export default MultiTableController.extend({
   },{
     id: 'status',
     headerTitle: 'Status',
-    contentPath: 'status',
+    contentPath: 'finalStatus',
   },{
     id: 'progress',
     headerTitle: 'Progress',
@@ -124,7 +126,7 @@ export default MultiTableController.extend({
     // Add process(vertex) dependencies based on dagPlan
     dagPlanEdges.forEach(function (edge) {
       var process = processHash[edge.outputVertexName];
-      if(process) {
+      if(process && processHash[edge.inputVertexName]) {
         process.blockers.push(processHash[edge.inputVertexName]);
       }
     });
@@ -132,17 +134,9 @@ export default MultiTableController.extend({
     return Ember.A(processes);
   }),
 
-  eventBars: [{
-    fromEvent: "VERTEX_TASK_START",
-    toEvent: "VERTEX_TASK_FINISH",
-  }, {
-    fromEvent: "BLOCKING_VERTICES_COMPLETE",
-    toEvent: "VERTEX_TASK_FINISH",
-  }],
-
   actions: {
     toggleFullscreen: function () {
-      var swimlaneElement = Ember.$(".swimlane-page")[0];
+      var swimlaneElement = Ember.$(".swimlane-page").get(0);
       if(swimlaneElement){
         fullscreen.toggle(swimlaneElement);
       }

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/controllers/dag/vertices.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/controllers/dag/vertices.js b/tez-ui2/src/main/webapp/app/controllers/dag/vertices.js
index 306d606..283f2d1 100644
--- a/tez-ui2/src/main/webapp/app/controllers/dag/vertices.js
+++ b/tez-ui2/src/main/webapp/app/controllers/dag/vertices.js
@@ -44,7 +44,7 @@ export default MultiTableController.extend({
   },{
     id: 'status',
     headerTitle: 'Status',
-    contentPath: 'status',
+    contentPath: 'finalStatus',
     cellComponentName: 'em-table-status-cell',
     observePath: true
   },{

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/models/vertex-am.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/models/vertex-am.js b/tez-ui2/src/main/webapp/app/models/vertex-am.js
index 69d2346..a20d171 100644
--- a/tez-ui2/src/main/webapp/app/models/vertex-am.js
+++ b/tez-ui2/src/main/webapp/app/models/vertex-am.js
@@ -29,4 +29,10 @@ export default AMModel.extend({
   failedTaskAttempts: DS.attr("number"),
   killedTaskAttempts: DS.attr("number"),
 
+  initTime: DS.attr('number'),
+  startTime: DS.attr('number'),
+  endTime: DS.attr('number'),
+  firstTaskStartTime: DS.attr('number'),
+  lastTaskFinishTime: DS.attr('number'),
+
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/models/vertex.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/models/vertex.js b/tez-ui2/src/main/webapp/app/models/vertex.js
index 647241f..e54bff2 100644
--- a/tez-ui2/src/main/webapp/app/models/vertex.js
+++ b/tez-ui2/src/main/webapp/app/models/vertex.js
@@ -59,13 +59,33 @@ export default AMTimelineModel.extend({
 
   name: DS.attr('string'),
 
-  firstTaskStartTime: DS.attr('number'),
-  lastTaskFinishTime: DS.attr('number'),
+  _initTime: DS.attr('number'),
+  _startTime: DS.attr('number'),
+  _endTime: DS.attr('number'),
+  _firstTaskStartTime: DS.attr('number'),
+  _lastTaskFinishTime: DS.attr('number'),
+
+  initTime: Ember.computed("am.initTime", "_initTime",
+    valueComputerFactory("am.initTime", "_initTime")
+  ),
+  startTime: Ember.computed("am.startTime", "_startTime",
+    valueComputerFactory("am.startTime", "_startTime")
+  ),
+  endTime: Ember.computed("am.endTime", "_endTime",
+    valueComputerFactory("am.endTime", "_endTime")
+  ),
+  firstTaskStartTime: Ember.computed("am.firstTaskStartTime", "_firstTaskStartTime",
+    valueComputerFactory("am.firstTaskStartTime", "_firstTaskStartTime")
+  ),
+  lastTaskFinishTime: Ember.computed("am.lastTaskFinishTime", "_lastTaskFinishTime",
+    valueComputerFactory("am.lastTaskFinishTime", "_lastTaskFinishTime")
+  ),
 
   totalTasks: DS.attr('number'),
   _failedTasks: DS.attr('number'),
   _succeededTasks: DS.attr('number'),
   _killedTasks: DS.attr('number'),
+
   failedTasks: Ember.computed("am.failedTasks", "_failedTasks",
     valueComputerFactory("am.failedTasks", "_failedTasks")
   ),
@@ -76,6 +96,14 @@ export default AMTimelineModel.extend({
     valueComputerFactory("am.killedTasks", "_killedTasks")
   ),
 
+  finalStatus: Ember.computed("status", "failedTaskAttempts", function () {
+    var status = this.get("status");
+    if(status === "SUCCEEDED" && this.get("failedTaskAttempts")) {
+      status = "SUCCEEDED_WITH_FAILURES";
+    }
+    return status;
+  }),
+
   runningTasks: Ember.computed("am.runningTasks", "status", function () {
     var runningTasks = this.get("am.runningTasks");
     if(runningTasks === undefined) {

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/routes/dag/swimlane.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/dag/swimlane.js b/tez-ui2/src/main/webapp/app/routes/dag/swimlane.js
index f8010f3..c79b00c 100644
--- a/tez-ui2/src/main/webapp/app/routes/dag/swimlane.js
+++ b/tez-ui2/src/main/webapp/app/routes/dag/swimlane.js
@@ -33,5 +33,19 @@ export default MultiAmPollsterRoute.extend({
     return this.get("loader").query('vertex', {
       dagID: this.modelFor("dag").get("id")
     }, options);
-  }
+  },
+
+  _loadedValueObserver: Ember.observer("loadedValue", function () {
+    var loadedValue = this.get("loadedValue"),
+        records = [];
+
+    if(loadedValue) {
+      loadedValue.forEach(function (record) {
+        records.push(record);
+      });
+
+      this.set("polledRecords", records);
+    }
+  }),
+
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/serializers/vertex-am.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/serializers/vertex-am.js b/tez-ui2/src/main/webapp/app/serializers/vertex-am.js
index ba160d2..3cf7a7e 100644
--- a/tez-ui2/src/main/webapp/app/serializers/vertex-am.js
+++ b/tez-ui2/src/main/webapp/app/serializers/vertex-am.js
@@ -26,5 +26,11 @@ export default AMSerializer.extend({
     runningTasks: "runningTasks",
     failedTaskAttempts: "failedTaskAttempts",
     killedTaskAttempts: "killedTaskAttempts",
+
+    initTime: "initTime",
+    startTime: "startTime",
+    endTime: "finishTime",
+    firstTaskStartTime: "firstTaskStartTime",
+    lastTaskFinishTime: "lastTaskFinishTime",
   }
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/serializers/vertex.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/serializers/vertex.js b/tez-ui2/src/main/webapp/app/serializers/vertex.js
index eac6808..a3cb22f 100644
--- a/tez-ui2/src/main/webapp/app/serializers/vertex.js
+++ b/tez-ui2/src/main/webapp/app/serializers/vertex.js
@@ -29,8 +29,11 @@ export default TimelineSerializer.extend({
   maps: {
     name: 'otherinfo.vertexName',
 
-    firstTaskStartTime: 'otherinfo.stats.firstTaskStartTime',
-    lastTaskFinishTime: 'otherinfo.stats.lastTaskFinishTime',
+    _initTime: 'otherinfo.initTime',
+    _startTime: 'otherinfo.startTime',
+    _endTime: 'otherinfo.endTime',
+    _firstTaskStartTime: 'otherinfo.stats.firstTaskStartTime',
+    _lastTaskFinishTime: 'otherinfo.stats.lastTaskFinishTime',
 
     totalTasks: 'otherinfo.numTasks',
     _failedTasks: 'otherinfo.numFailedTasks',

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/app.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/app.less b/tez-ui2/src/main/webapp/app/styles/app.less
index 7275650..c881553 100644
--- a/tez-ui2/src/main/webapp/app/styles/app.less
+++ b/tez-ui2/src/main/webapp/app/styles/app.less
@@ -16,6 +16,14 @@
  * limitations under the License.
  */
 
+@import "bower_components/bootstrap/less/bootstrap";
+@import "bower_components/font-awesome/less/font-awesome";
+
+@import "bower_components/snippet-ss/less/force";
+@import "bower_components/snippet-ss/less/effects";
+@import "bower_components/snippet-ss/less/no";
+@import "bower_components/snippet-ss/less/background";
+
 // Prerequisites
 @import "colors";
 @import "shared";
@@ -31,6 +39,8 @@
 @import "date-formatter";
 @import "em-swimlane";
 @import "em-tooltip";
+@import "em-swimlane-vertex-name";
+@import "em-table-status-cell";
 
 // Modals
 @import "column-selector";

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/column-selector.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/column-selector.less b/tez-ui2/src/main/webapp/app/styles/column-selector.less
index eb61128..747ed48 100644
--- a/tez-ui2/src/main/webapp/app/styles/column-selector.less
+++ b/tez-ui2/src/main/webapp/app/styles/column-selector.less
@@ -16,9 +16,6 @@
  * limitations under the License.
  */
 
-@import "bower_components/snippet-ss/less/force";
-@import "bower_components/snippet-ss/less/effects";
-
 .column-selector {
   .message {
     position: absolute;

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/details-page.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/details-page.less b/tez-ui2/src/main/webapp/app/styles/details-page.less
index dccec06..75d5e11 100644
--- a/tez-ui2/src/main/webapp/app/styles/details-page.less
+++ b/tez-ui2/src/main/webapp/app/styles/details-page.less
@@ -16,8 +16,6 @@
  * limitations under the License.
  */
 
-@import "bower_components/snippet-ss/less/no";
-
 .detail-list {
   display: inline-block;
   vertical-align: top;

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/em-swimlane-vertex-name.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/em-swimlane-vertex-name.less b/tez-ui2/src/main/webapp/app/styles/em-swimlane-vertex-name.less
new file mode 100644
index 0000000..249a8f1
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/styles/em-swimlane-vertex-name.less
@@ -0,0 +1,65 @@
+/**
+ * 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.
+ */
+
+.em-swimlane-vertex-name {
+
+  cursor: pointer;
+
+  direction: rtl;
+  text-align: right;
+
+  padding: 5px 5px 0px 0px;
+  white-space: nowrap;
+
+  height: 30px;
+
+  .name-text {
+    display: inline-block;
+    vertical-align: baseline;
+
+    &.ellipsis:after {
+      content:"\2026";
+      margin-right: -4px;
+    }
+  }
+
+  .em-table-status-cell {
+    display: inline-block;
+    vertical-align: text-top;
+
+    direction: ltr;
+
+    .status {
+      display: inline-block;
+
+      padding: 2px;
+
+      width: 16px;
+      height: 16px;
+      overflow: hidden;
+      border-radius: 10px;
+    }
+
+    .status-icon {
+      display: inline-block;
+      width: 12px;
+      margin-top: 2px;
+    }
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/em-swimlane.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/em-swimlane.less b/tez-ui2/src/main/webapp/app/styles/em-swimlane.less
index 2deb4db..b229a82 100644
--- a/tez-ui2/src/main/webapp/app/styles/em-swimlane.less
+++ b/tez-ui2/src/main/webapp/app/styles/em-swimlane.less
@@ -21,11 +21,16 @@
 .em-swimlane {
   position: relative;
 
-  margin: 5px 0px 5px 0px;
+  margin: 5px 0px 40px 0px;
 
   .process-names {
     width: 100px;
     border-right: 1px solid @border-color;
+
+    .consolidated-view-label {
+      margin-top: 20px;
+      padding-bottom: 10px;
+    }
   }
   .process-visuals {
     .force-scrollbar;
@@ -35,6 +40,93 @@
     right: 0px;
     top: 0px;
     overflow: auto;
+
+    .consolidated-view {
+      position: relative;
+      margin: 20px 10px 2px 10px;
+      height: 20px;
+      border: 1px solid @border-color;
+      border-radius: 2px;
+    }
+  }
+
+  .em-swimlane-ruler {
+    margin: 9px 10px 5px 10px;
+
+    .ruler-line {
+      margin: 0px -10px 0px -10px;
+      border-top: 1px solid @border-color;
+    }
+
+    .unit-text {
+      display: inline-block;
+      position: relative;
+      transition: left .5sec ease-out;
+    }
+
+    .mark-container {
+      overflow: hidden;
+      font-size: 0;
+      overflow: hidden;
+      white-space: nowrap;
+
+      .ruler-mark {
+        display: inline-block;
+        border-left: 1px solid @border-color;
+
+        margin-right: -1px;
+        margin-bottom: -2px;
+
+        font-size: 12px;
+
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+
+        .sub-marks {
+          display: block;
+          padding: 0px;
+
+          margin-bottom: -8px;
+
+          li {
+            vertical-align: top;
+            display: inline-block;
+            width: 10%;
+            height: 5px;
+            border-left: 1px solid @border-lite;
+
+            &:first-child {
+              border-left: none;
+            }
+
+            &:nth-child(2n) {
+              height: 8px;
+            }
+            &:nth-child(6) {
+              height: 12px;
+            }
+          }
+        }
+      }
+    }
+
+  }
+}
+
+.em-swimlane-consolidated-process {
+  position: absolute;
+  cursor: pointer;
+
+  top: 0px;
+  bottom: 0px;
+  border: 1px solid white;
+
+  transition: top .2s;
+  &.focused {
+    top: -10px;
+    border-top-left-radius: 5px;
+    border-top-right-radius: 5px;
   }
 }
 
@@ -54,28 +146,32 @@
   position: relative;
   height: 30px;
 
-  margin: 0px 10px;
+  // Gives a mouse sensitive margin to the left and right,
+  // so that event lines appear with a padding
+  border-left: 10px solid transparent;
+  border-right: 10px solid transparent;
 
   .process-line, .event-bar, .event-bubble {
     cursor: pointer;
   }
-
   .base-line {
     position: relative;
     height: 1px;
-    margin-left: -10px;
+    margin: 0px -10px;
     top: unit(unit(@process-height) * 0.5, get-unit(@process-height));
     border-top: 1px dotted @border-color;
   }
 
-  .process-line {
+  .process-line, .event-bar, .em-swimlane-event, .em-swimlane-blocking-event {
     position: absolute;
+  }
+
+  .process-line {
     top: unit(unit(@process-height) * 0.5 - 1, get-unit(@process-height));
     height: 3px;
   }
 
   .event-bar {
-    position: absolute;
     top: unit((unit(@process-height) * 0.5) - 10, get-unit(@process-height));
     height: 20px;
     background-color: @border-lite;
@@ -85,7 +181,6 @@
   }
 
   .em-swimlane-event {
-    position: absolute;
     top: unit(unit(@process-height) * 0.5, get-unit(@process-height));
 
     .event-line {
@@ -113,7 +208,6 @@
   }
 
   .em-swimlane-blocking-event {
-    position: absolute;
     top: unit(unit(@process-height) * 0.5, get-unit(@process-height));
 
     .event-line {

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/em-table-status-cell.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/em-table-status-cell.less b/tez-ui2/src/main/webapp/app/styles/em-table-status-cell.less
new file mode 100644
index 0000000..e3a26f7
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/styles/em-table-status-cell.less
@@ -0,0 +1,99 @@
+/**
+ * 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.
+ */
+
+.fa-icon(@name) {
+  @content: "fa-var-@{name}";
+  &:before {content: @@content}
+}
+
+.em-table-status-cell {
+  overflow: visible !important;
+
+  .status {
+    .label;
+    .label-default;
+  }
+  .status-icon {
+    .fa;
+    .fa-icon(exclamation);
+  }
+
+  .status-new, .status-inited {
+    .status-icon {
+      .fa-icon(plus);
+    }
+  }
+
+  .status-initializing, .status-scheduled, .status-start-wait {
+    .label-primary;
+    .status-icon {
+      .fa-icon(history);
+    }
+  }
+
+  .status-running {
+    .diagonal-stripes-bg;
+    .animate;
+    .label-info;
+    .status-icon {
+      .fa-icon(spinner);
+    }
+  }
+
+  .status-committing {
+    .label-info;
+    .status-icon {
+      .fa-icon(save);
+    }
+  }
+
+  .status-succeeded, .status-succeeded-with-failures {
+    .label-success;
+    .status-icon {
+      .fa-icon(check);
+    }
+  }
+  .status-succeeded-with-failures {
+    .label-warning;
+  }
+
+  .status-terminating {
+    .label-warning;
+    .status-icon {
+      .fa-icon(exclamation-triangle);
+    }
+  }
+
+  .status-failed, .status-fail-in-progress {
+    .label-warning;
+    .status-icon {
+      .fa-icon(exclamation);
+    }
+  }
+
+  .status-kill-wait, .status-kill-in-progress, .status-killed, .status-error {
+    .label-warning;
+    .status-icon {
+      .fa-icon(ban);
+    }
+  }
+  .status-killed, .status-error {
+    .label-danger;
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/em-tooltip.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/em-tooltip.less b/tez-ui2/src/main/webapp/app/styles/em-tooltip.less
index ab2a19e..3f7ed87 100644
--- a/tez-ui2/src/main/webapp/app/styles/em-tooltip.less
+++ b/tez-ui2/src/main/webapp/app/styles/em-tooltip.less
@@ -20,6 +20,8 @@
   .no-select;
   .no-mouse;
 
+  z-index: 9007199254740991;
+
   position: fixed;
   width: 820px; //2 * (td width + padding)
 

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/page-layout.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/page-layout.less b/tez-ui2/src/main/webapp/app/styles/page-layout.less
index ee62535..7249903 100644
--- a/tez-ui2/src/main/webapp/app/styles/page-layout.less
+++ b/tez-ui2/src/main/webapp/app/styles/page-layout.less
@@ -16,9 +16,6 @@
  * limitations under the License.
  */
 
-@import "colors";
-@import "bower_components/snippet-ss/less/no";
-
 body, html, body > .ember-view {
   height: 100%;
   overflow: visible;

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/shared.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/shared.less b/tez-ui2/src/main/webapp/app/styles/shared.less
index 5f4b8f4..acaa9c3 100644
--- a/tez-ui2/src/main/webapp/app/styles/shared.less
+++ b/tez-ui2/src/main/webapp/app/styles/shared.less
@@ -16,8 +16,6 @@
  * limitations under the License.
  */
 
-@import "colors";
-
 b {
   font-weight: bold;
 }

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/swimlane-page.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/swimlane-page.less b/tez-ui2/src/main/webapp/app/styles/swimlane-page.less
index c9ae374..3f14b39 100644
--- a/tez-ui2/src/main/webapp/app/styles/swimlane-page.less
+++ b/tez-ui2/src/main/webapp/app/styles/swimlane-page.less
@@ -17,6 +17,7 @@
  */
 
 .swimlane-page {
+
   .button-panel {
     .no-select;
 
@@ -66,6 +67,8 @@
     height: 100%;
     width: 100%;
 
+    overflow: auto;
+
     padding: 10px;
 
     .fa-compress {

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/tab-n-refresh.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/tab-n-refresh.less b/tez-ui2/src/main/webapp/app/styles/tab-n-refresh.less
index 16ad404..97acff0 100644
--- a/tez-ui2/src/main/webapp/app/styles/tab-n-refresh.less
+++ b/tez-ui2/src/main/webapp/app/styles/tab-n-refresh.less
@@ -16,8 +16,6 @@
  * limitations under the License.
  */
 
-@import "./shared";
-
 .tab-n-refresh {
   margin-bottom: 10px;
   position: relative;

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/styles/table-controls.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/table-controls.less b/tez-ui2/src/main/webapp/app/styles/table-controls.less
index aa9f9e6..2f0371f 100644
--- a/tez-ui2/src/main/webapp/app/styles/table-controls.less
+++ b/tez-ui2/src/main/webapp/app/styles/table-controls.less
@@ -16,8 +16,6 @@
  * limitations under the License.
  */
 
-@import "shared";
-
 .table-controls {
   .left-delim;
 

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-consolidated-process.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-consolidated-process.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-consolidated-process.hbs
new file mode 100644
index 0000000..0507469
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-consolidated-process.hbs
@@ -0,0 +1,19 @@
+{{!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+}}
+
+&nbsp;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs
index cbb025c..5f2f204 100644
--- a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs
+++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-process-visual.hbs
@@ -19,8 +19,7 @@
 <div class="base-line"></div>
 {{em-swimlane-process-line
   process=process
-  startEvent=startEvent
-  endEvent=endEvent
+  processor=processor
   showTooltip="showTooltip"
   hideTooltip="hideTooltip"
   click="click"
@@ -29,28 +28,28 @@
   {{em-swimlane-blocking-event
     process=process
     blocking=blocking
-    events=normalizedEvents
+    processor=processor
     showTooltip="showTooltip"
     hideTooltip="hideTooltip"
     click="click"
   }}
 {{/each}}
-{{#each eventBars as |bar index|}}
+{{#each process.eventBars as |bar index|}}
   {{em-swimlane-event-bar
-    events=normalizedEvents
     bar=bar
     barIndex=index
-    bars=eventBars
     process=process
+    processor=processor
     showTooltip="showTooltip"
     hideTooltip="hideTooltip"
     click="click"
   }}
 {{/each}}
-{{#each normalizedEvents as |event|}}
+{{#each process.events as |event|}}
   {{em-swimlane-event
     process=process
     event=event
+    processor=processor
     showTooltip="showTooltip"
     hideTooltip="hideTooltip"
     click="click"

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-ruler.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-ruler.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-ruler.hbs
new file mode 100644
index 0000000..d832c13
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-ruler.hbs
@@ -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.
+}}
+
+<div class="ruler-line"></div>
+<div class="mark-container">
+  {{#each marks as |mark|}}
+    <div class="ruler-mark" style={{markDef.style}}>
+      <ul class="sub-marks"><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li><li></li></ul>
+      &nbsp;{{mark.duration}}
+    </div>
+  {{/each}}
+</div>
+<div class="unit-text" style={{unitTextStyle}}>
+  {{markDef.unit}}
+</div>

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-vertex-name.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-vertex-name.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-vertex-name.hbs
new file mode 100644
index 0000000..8c977ee
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane-vertex-name.hbs
@@ -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.
+}}
+
+{{progressText}}
+{{em-table-status-cell content=process.vertex.finalStatus}}
+<span class="name-text {{if useEllipsis 'ellipsis'}}">
+  {{processName}}
+</span>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs
index ad0cbe2..e55c202 100644
--- a/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs
+++ b/tez-ui2/src/main/webapp/app/templates/components/em-swimlane.hbs
@@ -18,26 +18,45 @@
 
 <div class="process-names">
   {{#each normalizedProcesses as |process|}}
-    {{em-swimlane-process-name
+    {{component nameComponent
       process=process
+      showTooltip="showTooltip"
+      hideTooltip="hideTooltip"
       click="click"
     }}
   {{/each}}
+  <div class="consolidated-view-label">
+    Consolidated
+  </div>
 </div><div class="process-visuals">
   <div class="zoom-panel">
     {{#each normalizedProcesses as |process|}}
-      {{em-swimlane-process-visual
+      {{component visualComponent
         process=process
-        definition=processDefinition
-        eventBars=eventBars
-        startTime=startTime
-        endTime=endTime
-        timeWindow=timeWindow
+        processor=processor
         showTooltip="showTooltip"
         hideTooltip="hideTooltip"
         click="click"
       }}
     {{/each}}
+
+    {{#if consolidate}}
+      <div class="consolidated-view">
+        {{#each normalizedProcesses as |process|}}
+          {{em-swimlane-consolidated-process
+            focusedProcess=focusedProcess
+            process=process
+            processor=processor
+            showTooltip="showTooltip"
+            hideTooltip="hideTooltip"
+            click="click"
+          }}
+        {{/each}}
+      </div>
+    {{/if}}
+
+    {{em-swimlane-ruler scroll=scroll processor=processor zoom=zoom}}
+
   </div>
 </div>
 

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/templates/components/em-table-status-cell.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/components/em-table-status-cell.hbs b/tez-ui2/src/main/webapp/app/templates/components/em-table-status-cell.hbs
index f720178..9783b6c 100644
--- a/tez-ui2/src/main/webapp/app/templates/components/em-table-status-cell.hbs
+++ b/tez-ui2/src/main/webapp/app/templates/components/em-table-status-cell.hbs
@@ -17,7 +17,10 @@
 }}
 
 {{#if content}}
-  <span class="label label-{{statusType}}">{{content}}</span>
+  <span class="status {{statusName}}">
+    <i class="status-icon"></i>
+    {{content}}
+  </span>
 {{else}}
   <span class="txt-message"> Not Available! </span>
 {{/if}}

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs b/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs
index 6d9b885..7c50e81 100644
--- a/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs
+++ b/tez-ui2/src/main/webapp/app/templates/dag/swimlane.hbs
@@ -31,11 +31,10 @@
     {{em-swimlane
       columns=visibleColumns
       processes=processes
-      eventBars=eventBars
-      startTime=model.firstObject.dag.startTime
-      endTime=model.firstObject.dag.endTime
+      nameComponent="em-swimlane-vertex-name"
       zoom=zoom
       click="click"
+      consolidate=true
     }}
   </div>
 {{else}}

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/templates/vertex/index.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/vertex/index.hbs b/tez-ui2/src/main/webapp/app/templates/vertex/index.hbs
index 2955882..15ffde3 100644
--- a/tez-ui2/src/main/webapp/app/templates/vertex/index.hbs
+++ b/tez-ui2/src/main/webapp/app/templates/vertex/index.hbs
@@ -38,7 +38,7 @@
       </tr>
       <tr>
         <td>Status</td>
-        <td>{{em-table-status-cell content=model.status}}</td>
+        <td>{{em-table-status-cell content=model.finalStatus}}</td>
       </tr>
       <tr>
         <td>Progress</td>

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/utils/process.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/utils/process.js b/tez-ui2/src/main/webapp/app/utils/process.js
index d0f06a7..2920f39 100644
--- a/tez-ui2/src/main/webapp/app/utils/process.js
+++ b/tez-ui2/src/main/webapp/app/utils/process.js
@@ -23,7 +23,8 @@ export default Ember.Object.extend({
   _id: null,
 
   name: null,
-  events: null,
+  events: [],
+  eventBars: null,
 
   index: 0,
   color: null,
@@ -31,6 +32,11 @@ export default Ember.Object.extend({
   blockers: null, // Array of processes that's blocking the current process
   blocking: null, // Array of processes blocked by the current process
 
+  blockingEventName: null,
+
+  consolidateStartTime: Ember.computed.oneWay("startEvent.time"),
+  consolidateEndTime: Ember.computed.oneWay("endEvent.time"),
+
   init: function () {
     this.set("_id", `process-id-${processIndex}`);
     processIndex++;
@@ -50,6 +56,14 @@ export default Ember.Object.extend({
     return `hsl( ${color.h}, ${color.s}%, ${l}% )`;
   },
 
+  getBarColor: function (barIndex) {
+    return this.getColor(1 - (barIndex / this.get("eventBars.length")));
+  },
+
+  getConsolidateColor: function () {
+    return this.getColor();
+  },
+
   startEvent: Ember.computed("events.@each.time", function () {
     var events = this.get("events"),
         startEvent;

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/utils/processor.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/utils/processor.js b/tez-ui2/src/main/webapp/app/utils/processor.js
new file mode 100644
index 0000000..6658579
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/utils/processor.js
@@ -0,0 +1,50 @@
+/**
+ * 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';
+
+function getVibrantHSL(colorNum, totalColors) {
+  if (totalColors < 1){
+    totalColors = 1;
+  }
+  return {
+    h: colorNum * (360 / totalColors) % 360,
+    s: 100 - (colorNum % 2) * 30,
+    l: 40
+  };
+}
+
+export default Ember.Object.extend({
+
+  processCount: 0,
+
+  startTime: 0,
+  endTime: 0,
+
+  timeWindow: Ember.computed("startTime", "endTime", function () {
+    return Math.max(0, this.get("endTime") - this.get("startTime"));
+  }),
+
+  createProcessColor: function (index, totalProcessCount) {
+    return getVibrantHSL(index, totalProcessCount || this.get("processCount"));
+  },
+
+  timeToPositionPercent: function (time) {
+    return ((time - this.get("startTime")) / this.get("timeWindow")) * 100;
+  }
+
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/app/utils/vertex-process.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/utils/vertex-process.js b/tez-ui2/src/main/webapp/app/utils/vertex-process.js
index b99c822..64de314 100644
--- a/tez-ui2/src/main/webapp/app/utils/vertex-process.js
+++ b/tez-ui2/src/main/webapp/app/utils/vertex-process.js
@@ -1,3 +1,4 @@
+/*global more*/
 /**
  * Licensed to the Apache Software Foundation (ASF) under one or more
  * contributor license agreements. See the NOTICE file distributed with this
@@ -19,14 +20,7 @@ import Ember from 'ember';
 
 import Process from './process';
 
-const EVENT_TEXTS = {
-  VERTEX_INITIALIZED: "Initialized",
-  VERTEX_STARTED: "Started",
-  VERTEX_FINISHED: "Finished",
-  VERTEX_TASK_START: "First Task Start",
-  VERTEX_TASK_FINISH: "All Tasks Complete",
-  BLOCKING_VERTICES_COMPLETE: "All Blocking Vertices Complete"
-};
+var MoreObject = more.Object;
 
 export default Process.extend({
   vertex: null,
@@ -38,50 +32,94 @@ export default Process.extend({
 
   getVisibleProps: null,
 
-  events: Ember.computed(
-    "vertex.events.@each.timestamp",
-    "vertex.firstTaskStartTime",
-    "vertex.lastTaskFinishTime",
-    "unblockTime",
+  eventBars: [{
+    fromEvent: "VERTEX_TASK_START",
+    toEvent: "VERTEX_TASK_FINISH",
+  }, {
+    fromEvent: "DEPENDENT_VERTICES_COMPLETE",
+    toEvent: "VERTEX_TASK_FINISH",
+  }],
+
+  eventsHash: Ember.computed("vertex.events.@each.timestamp", function () {
+    var events = {},
+        eventsArr = this.get("vertex.events");
+
+    if(eventsArr) {
+      eventsArr.forEach(function (event) {
+        if(event.timestamp > 0) {
+          events[event.eventtype] = {
+            name: event.eventtype,
+            time: event.timestamp,
+            info: event.eventinfo
+          };
+        }
+      });
+    }
+
+    return events;
+  }),
+
+  events: Ember.computed("eventsHash",
+    "vertex.initTime", "vertex.startTime", "vertex.endTime",
+    "vertex.firstTaskStartTime", "vertex.lastTaskFinishTime", "unblockTime",
     function () {
-      var events = this.get("vertex.events").map(function (event) {
-        return {
-          name: event.eventtype,
-          text: EVENT_TEXTS[event.eventtype],
-          time: event.timestamp
+      var events = [],
+          eventsHash = this.get("eventsHash"),
+
+          initTime = this.get("vertex.initTime"),
+          startTime = this.get("vertex.startTime"),
+          endTime = this.get("vertex.endTime"),
+
+          firstTaskStartTime = this.get("vertex.firstTaskStartTime"),
+          lastTaskFinishTime = this.get("vertex.lastTaskFinishTime"),
+          unblockTime = this.get("unblockTime");
+
+      if(initTime > 0) {
+        eventsHash["VERTEX_INITIALIZED"] = {
+          name: "VERTEX_INITIALIZED",
+          time: initTime
+        };
+      }
+
+      if(startTime > 0) {
+        eventsHash["VERTEX_STARTED"] = {
+          name: "VERTEX_STARTED",
+          time: startTime
         };
-      }),
-      firstTaskStartTime = this.get("vertex.firstTaskStartTime"),
-      lastTaskFinishTime = this.get("vertex.lastTaskFinishTime"),
-      unblockTime = this.get("unblockTime");
-
-      if(firstTaskStartTime) {
-        let type = "VERTEX_TASK_START";
-        events.push({
-          name: type,
-          text: EVENT_TEXTS[type],
+      }
+
+      if(firstTaskStartTime > 0) {
+        eventsHash["VERTEX_TASK_START"] = {
+          name: "VERTEX_TASK_START",
           time: firstTaskStartTime
-        });
+        };
       }
 
-      if(lastTaskFinishTime) {
-        let type = "VERTEX_TASK_FINISH";
-        events.push({
-          name: type,
-          text: EVENT_TEXTS[type],
+      if(unblockTime > 0 && unblockTime >= firstTaskStartTime) {
+        eventsHash["DEPENDENT_VERTICES_COMPLETE"] = {
+          name: "DEPENDENT_VERTICES_COMPLETE",
+          time: unblockTime
+        };
+      }
+
+      if(lastTaskFinishTime > 0) {
+        eventsHash["VERTEX_TASK_FINISH"] = {
+          name: "VERTEX_TASK_FINISH",
           time: lastTaskFinishTime
-        });
+        };
       }
 
-      if(unblockTime && unblockTime >= firstTaskStartTime) {
-        let type = "BLOCKING_VERTICES_COMPLETE";
-        events.push({
-          name: type,
-          text: EVENT_TEXTS[type],
-          time: unblockTime
-        });
+      if(endTime > 0) {
+        eventsHash["VERTEX_FINISHED"] = {
+          name: "VERTEX_FINISHED",
+          time: endTime
+        };
       }
 
+      MoreObject.forEach(eventsHash, function (key, value) {
+        events.push(value);
+      });
+
       return events;
     }
   ),
@@ -110,11 +148,16 @@ export default Process.extend({
 
   getTooltipContents: function (type, options) {
     var contents,
-        that = this;
+        that = this,
+        vertexDescription;
 
     switch(type) {
+      case "consolidated-process":
+        vertexDescription = `Contribution ${options.contribution}%`;
+        /* falls through */
       case "event-bar":
       case "process-line":
+      case "process-name":
         let properties = this.getVisibleProps().map(function (definition) {
           return {
             name: definition.get("headerTitle"),
@@ -126,27 +169,54 @@ export default Process.extend({
 
         contents = [{
           title: this.get("name"),
-          properties: properties
+          properties: properties,
+          description: vertexDescription
         }];
       break;
       case "event":
         contents = options.events.map(function (event) {
+          var properties = [{
+            name: "Time",
+            value: event.time,
+            type: "date"
+          }];
+
+          if(event.info) {
+            MoreObject.forEach(event.info, function (key, value) {
+              if(MoreObject.isString(value)) {
+                properties.push({
+                  name: key,
+                  value: value,
+                });
+              }
+              else if (MoreObject.isNumber(value)) {
+                properties.push({
+                  name: key,
+                  value: value,
+                  type: "number"
+                });
+              }
+            });
+          }
           return {
-            title: event.text,
-            properties: [{
-              name: "Type",
-              value: event.name,
-            }, {
-              name: "Time",
-              value: event.time,
-              type: "date"
-            }]
+            title: event.name,
+            properties: properties
           };
         });
       break;
     }
 
     return contents;
-  }
+  },
+
+  consolidateStartTime: Ember.computed("vertex.firstTaskStartTime",
+      "vertex.unblockTime", function () {
+        return Math.max(this.get("vertex.firstTaskStartTime") || 0, this.get("unblockTime") || 0);
+  }),
+  consolidateEndTime: Ember.computed.oneWay("vertex.endTime"),
+
+  getConsolidateColor: function () {
+    return this.getBarColor(this.get("unblockTime") ? 1 : 0);
+  },
 
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js
index 3ffab01..1659ddc 100644
--- a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js
+++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-blocking-event-test.js
@@ -18,8 +18,10 @@
 
 import { moduleForComponent, test } from 'ember-qunit';
 import hbs from 'htmlbars-inline-precompile';
+import wait from 'ember-test-helpers/wait';
 
 import Process from 'tez-ui/utils/process';
+import Processor from 'tez-ui/utils/processor';
 
 moduleForComponent('em-swimlane-blocking-event', 'Integration | Component | em swimlane blocking event', {
   integration: true
@@ -27,15 +29,15 @@ moduleForComponent('em-swimlane-blocking-event', 'Integration | Component | em s
 
 test('Basic creation test', function(assert) {
   this.set("process", Process.create());
-  this.set("events", []);
+  this.set("processor", Processor.create());
 
-  this.render(hbs`{{em-swimlane-blocking-event process=process events=events}}`);
+  this.render(hbs`{{em-swimlane-blocking-event processor=processor process=process}}`);
 
   assert.equal(this.$().text().trim(), '');
 
   // Template block usage:" + EOL +
   this.render(hbs`
-    {{#em-swimlane-blocking-event process=process events=events}}
+    {{#em-swimlane-blocking-event processor=processor process=process}}
       template block text
     {{/em-swimlane-blocking-event}}
   `);
@@ -55,24 +57,61 @@ test('Blocking test', function(assert) {
     getColor: function () {
       return processColor;
     },
-    events: []
+    events: [{
+      name: blockingEventName,
+      time: 2
+    }]
   }));
-  this.set("normalizedEvents", [{
-    name: "e1",
-    pos: 10
-  }, {
-    name: blockingEventName,
-    pos: 20
-  }, {
-    name: "e2",
-    pos: 30
-  }]);
   this.set("blocking", Process.create({
-    index: blockingIndex
+    index: blockingIndex,
+    endEvent: {
+      time: 5
+    }
+  }));
+  this.set("processor", Processor.create({
+    startTime: 0,
+    endTime: 10
+  }));
+
+  this.render(hbs`{{em-swimlane-blocking-event processor=processor process=process blocking=blocking}}`);
+
+  return wait().then(() => {
+    assert.equal(this.$(".em-swimlane-blocking-event").attr("style").trim(), 'left: 20%;');
+    assert.equal(this.$(".event-line").css("height"), ((blockingIndex - processIndex) * 30) + "px");
+  });
+});
+
+test('Blocking test with blocking.endEvent.time < blockTime', function(assert) {
+  var blockingEventName = "blockingEvent",
+      processIndex = 5,
+      blockingIndex = 7,
+      processColor = "#123456";
+
+  this.set("process", Process.create({
+    blockingEventName: blockingEventName,
+    index: processIndex,
+    getColor: function () {
+      return processColor;
+    },
+    events: [{
+      name: blockingEventName,
+      time: 5
+    }]
+  }));
+  this.set("blocking", Process.create({
+    index: blockingIndex,
+    endEvent: {
+      time: 2
+    }
+  }));
+  this.set("processor", Processor.create({
+    startTime: 0,
+    endTime: 10
   }));
 
-  this.render(hbs`{{em-swimlane-blocking-event process=process events=normalizedEvents blocking=blocking}}`);
+  this.render(hbs`{{em-swimlane-blocking-event processor=processor process=process blocking=blocking}}`);
 
-  assert.equal(this.$(".em-swimlane-blocking-event").attr("style").trim(), 'left: 20%;');
-  assert.equal(this.$(".event-line").css("height"), ((blockingIndex - processIndex) * 30) + "px");
+  return wait().then(() => {
+    assert.equal(this.$(".em-swimlane-blocking-event").attr("style"), undefined);
+  });
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-consolidated-process-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-consolidated-process-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-consolidated-process-test.js
new file mode 100644
index 0000000..5fe79a5
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-consolidated-process-test.js
@@ -0,0 +1,61 @@
+/**
+ * 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 { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+import wait from 'ember-test-helpers/wait';
+
+import Process from 'tez-ui/utils/process';
+import Processor from 'tez-ui/utils/processor';
+
+moduleForComponent('em-swimlane-consolidated-process', 'Integration | Component | em swimlane consolidated process', {
+  integration: true
+});
+
+test('Basic creation test', function(assert) {
+  this.render(hbs`{{em-swimlane-consolidated-process}}`);
+
+  assert.equal(this.$().text().trim(), '');
+
+  // Template block usage:" + EOL +
+  this.render(hbs`
+    {{#em-swimlane-consolidated-process}}
+      template block text
+    {{/em-swimlane-consolidated-process}}
+  `);
+
+  assert.equal(this.$().text().trim(), '');
+});
+
+test('Basic creation test', function(assert) {
+  this.set("process", Process.create({
+    consolidateStartTime: 3,
+    consolidateEndTime: 6
+  }));
+  this.set("processor", Processor.create({
+    startTime: 0,
+    endTime: 10
+  }));
+
+  this.render(hbs`{{em-swimlane-consolidated-process process=process processor=processor}}`);
+
+  return wait().then(() => {
+    assert.equal(this.$(".em-swimlane-consolidated-process").attr("style").trim(),
+        "left: 30%; right: 40%; z-index: 30;");
+  });
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js
index d05924f..0e0eb1c 100644
--- a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js
+++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-bar-test.js
@@ -20,6 +20,7 @@ import { moduleForComponent, test } from 'ember-qunit';
 import hbs from 'htmlbars-inline-precompile';
 
 import Process from 'tez-ui/utils/process';
+import Processor from 'tez-ui/utils/processor';
 
 moduleForComponent('em-swimlane-event-bar', 'Integration | Component | em swimlane event bar', {
   integration: true
@@ -27,14 +28,15 @@ moduleForComponent('em-swimlane-event-bar', 'Integration | Component | em swimla
 
 test('Basic creation test', function(assert) {
   this.set("process", Process.create());
+  this.set("processor", Processor.create());
 
-  this.render(hbs`{{em-swimlane-event-bar process=process}}`);
+  this.render(hbs`{{em-swimlane-event-bar processor=processor process=process}}`);
 
   assert.equal(this.$().text().trim(), '');
 
   // Template block usage:" + EOL +
   this.render(hbs`
-    {{#em-swimlane-event-bar process=process}}
+    {{#em-swimlane-event-bar process=process processor=processor}}
       template block text
     {{/em-swimlane-event-bar}}
   `);

http://git-wip-us.apache.org/repos/asf/tez/blob/8e9e5ae7/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js
index 034d288..cee0b3d 100644
--- a/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js
+++ b/tez-ui2/src/main/webapp/tests/integration/components/em-swimlane-event-test.js
@@ -20,6 +20,7 @@ import { moduleForComponent, test } from 'ember-qunit';
 import hbs from 'htmlbars-inline-precompile';
 
 import Process from 'tez-ui/utils/process';
+import Processor from 'tez-ui/utils/processor';
 
 import wait from 'ember-test-helpers/wait';
 
@@ -29,15 +30,16 @@ moduleForComponent('em-swimlane-event', 'Integration | Component | em swimlane e
 
 test('Basic creation test', function(assert) {
   this.set("process", Process.create({}));
+  this.set("processor", Processor.create());
 
-  this.render(hbs`{{em-swimlane-event process=process}}`);
+  this.render(hbs`{{em-swimlane-event processor=processor process=process}}`);
 
   assert.ok(this.$(".event-bar"));
   assert.ok(this.$(".event-window"));
 
   // Template block usage:" + EOL +
   this.render(hbs`
-    {{#em-swimlane-event process=process}}
+    {{#em-swimlane-event process=process processor=processor}}
       template block text
     {{/em-swimlane-event}}
   `);
@@ -49,10 +51,14 @@ test('Basic creation test', function(assert) {
 test('Event position test', function(assert) {
   this.set("process", Process.create());
   this.set("event", {
-    pos: 60
+    time: 6
   });
+  this.set("processor", Processor.create({
+    startTime: 0,
+    endTime: 10
+  }));
 
-  this.render(hbs`{{em-swimlane-event process=process event=event}}`);
+  this.render(hbs`{{em-swimlane-event processor=processor process=process event=event}}`);
 
   return wait().then(() => {
     assert.equal(this.$(".em-swimlane-event").attr("style").trim(), "left: 60%;", "em-swimlane-event");


Mime
View raw message