Return-Path: X-Original-To: apmail-tez-commits-archive@minotaur.apache.org Delivered-To: apmail-tez-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 7112E192F0 for ; Tue, 5 Apr 2016 08:52:26 +0000 (UTC) Received: (qmail 85375 invoked by uid 500); 5 Apr 2016 08:52:26 -0000 Delivered-To: apmail-tez-commits-archive@tez.apache.org Received: (qmail 85292 invoked by uid 500); 5 Apr 2016 08:52:26 -0000 Mailing-List: contact commits-help@tez.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@tez.apache.org Delivered-To: mailing list commits@tez.apache.org Received: (qmail 85282 invoked by uid 99); 5 Apr 2016 08:52:26 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 05 Apr 2016 08:52:26 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 10B49E0995; Tue, 5 Apr 2016 08:52:26 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: sree@apache.org To: commits@tez.apache.org Date: Tue, 05 Apr 2016 08:52:27 -0000 Message-Id: <182c871b9e58473183553f9b7f6c3c4c@git.apache.org> In-Reply-To: References: X-Mailer: ASF-Git Admin Mailer Subject: [2/2] tez git commit: TEZ-3172. Tez UI: Swimlane - In progress & Shadow (sree) 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 Authored: Tue Apr 5 14:21:54 2016 +0530 Committer: Sreenath Somarajapuram 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. +}} + +  \ 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 @@
{{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. +}} + +
+
+ {{#each marks as |mark|}} +
+
+  {{mark.duration}} +
+ {{/each}} +
+
+ {{markDef.unit}} +
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}} + + {{processName}} + \ 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 @@
{{#each normalizedProcesses as |process|}} - {{em-swimlane-process-name + {{component nameComponent process=process + showTooltip="showTooltip" + hideTooltip="hideTooltip" click="click" }} {{/each}} +
+ Consolidated +
{{#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}} +
+ {{#each normalizedProcesses as |process|}} + {{em-swimlane-consolidated-process + focusedProcess=focusedProcess + process=process + processor=processor + showTooltip="showTooltip" + hideTooltip="hideTooltip" + click="click" + }} + {{/each}} +
+ {{/if}} + + {{em-swimlane-ruler scroll=scroll processor=processor zoom=zoom}} +
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}} - {{content}} + + + {{content}} + {{else}} Not Available! {{/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 }} {{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 @@ Status - {{em-table-status-cell content=model.status}} + {{em-table-status-cell content=model.finalStatus}} Progress 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");