You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tez.apache.org by sr...@apache.org on 2016/02/24 23:35:08 UTC
[31/45] tez git commit: TEZ-3069. Tez UI 2: Make error bar fully
functional (sree)
TEZ-3069. Tez UI 2: Make error bar fully functional (sree)
Project: http://git-wip-us.apache.org/repos/asf/tez/repo
Commit: http://git-wip-us.apache.org/repos/asf/tez/commit/6d4bb2c6
Tree: http://git-wip-us.apache.org/repos/asf/tez/tree/6d4bb2c6
Diff: http://git-wip-us.apache.org/repos/asf/tez/diff/6d4bb2c6
Branch: refs/heads/TEZ-2980
Commit: 6d4bb2c6366e01971ce07460664e88fa8344eb30
Parents: 963e77a
Author: Sreenath Somarajapuram <sr...@apache.org>
Authored: Sat Jan 30 19:55:25 2016 +0530
Committer: Sreenath Somarajapuram <sr...@apache.org>
Committed: Thu Feb 25 03:32:52 2016 +0530
----------------------------------------------------------------------
TEZ-2980-CHANGES.txt | 1 +
.../src/main/webapp/app/adapters/abstract.js | 15 +++
tez-ui2/src/main/webapp/app/adapters/am.js | 1 +
tez-ui2/src/main/webapp/app/adapters/rm.js | 1 +
.../src/main/webapp/app/adapters/timeline.js | 1 +
.../src/main/webapp/app/components/error-bar.js | 109 +++++++++++++++++++
.../main/webapp/app/controllers/application.js | 2 +
tez-ui2/src/main/webapp/app/entities/entity.js | 2 +
tez-ui2/src/main/webapp/app/routes/abstract.js | 12 +-
.../src/main/webapp/app/routes/am-pollster.js | 6 +-
tez-ui2/src/main/webapp/app/routes/app.js | 3 +-
.../src/main/webapp/app/routes/application.js | 2 +-
tez-ui2/src/main/webapp/app/routes/attempt.js | 3 +-
tez-ui2/src/main/webapp/app/routes/dag.js | 3 +-
.../main/webapp/app/routes/dag/index/index.js | 5 +
tez-ui2/src/main/webapp/app/routes/pollster.js | 18 +--
tez-ui2/src/main/webapp/app/routes/task.js | 3 +-
tez-ui2/src/main/webapp/app/routes/vertex.js | 3 +-
tez-ui2/src/main/webapp/app/styles/app.less | 8 +-
.../src/main/webapp/app/styles/error-bar.less | 102 +++++++++++++++++
.../main/webapp/app/templates/application.hbs | 3 +-
.../app/templates/components/error-bar.hbs | 31 ++++++
.../integration/components/error-bar-test.js | 43 ++++++++
.../webapp/tests/unit/entities/entity-test.js | 3 +
.../webapp/tests/unit/routes/abstract-test.js | 6 +-
25 files changed, 362 insertions(+), 24 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/TEZ-2980-CHANGES.txt
----------------------------------------------------------------------
diff --git a/TEZ-2980-CHANGES.txt b/TEZ-2980-CHANGES.txt
index fc99577..0457cb0 100644
--- a/TEZ-2980-CHANGES.txt
+++ b/TEZ-2980-CHANGES.txt
@@ -28,3 +28,4 @@ ALL CHANGES:
TEZ-3070. Tez UI 2: Jenkins build is failing
TEZ-3060. Tez UI 2: Activate auto-refresh
TEZ-3061. Tez UI 2: Display in-progress vertex table in DAG details
+ TEZ-3069. Tez UI 2: Make error bar fully functional
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/adapters/abstract.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/adapters/abstract.js b/tez-ui2/src/main/webapp/app/adapters/abstract.js
index 6cb701b..121d4ee 100644
--- a/tez-ui2/src/main/webapp/app/adapters/abstract.js
+++ b/tez-ui2/src/main/webapp/app/adapters/abstract.js
@@ -52,4 +52,19 @@ export default LoaderAdapter.extend({
Ember.assert(`Path not found for type:${type} to server:${serverName}`, path);
return path;
},
+
+ normalizeErrorResponse: function(status, headers, payload) {
+ var response;
+
+ if(payload && payload.exception && !payload.errors) {
+ payload = `${payload.exception}\n${payload.message}\n${payload.javaClassName}`;
+ response = this._super(status, headers, payload);
+ }
+ else {
+ response = this._super(status, headers, payload);
+ Ember.set(response, '0.title', this.get("outOfReachMessage"));
+ }
+
+ return response;
+ }
});
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/adapters/am.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/adapters/am.js b/tez-ui2/src/main/webapp/app/adapters/am.js
index 85f3d27..c4cb75d 100644
--- a/tez-ui2/src/main/webapp/app/adapters/am.js
+++ b/tez-ui2/src/main/webapp/app/adapters/am.js
@@ -20,6 +20,7 @@ import AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
serverName: "am",
+ outOfReachMessage: "Application Master (AM) is out of reach. Either it's down, or CORS is not enabled for YARN ResourceManager.",
queryRecord: function(store, type, query) {
return this.query(store, type, query);
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/adapters/rm.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/adapters/rm.js b/tez-ui2/src/main/webapp/app/adapters/rm.js
index b87c77d..252affb 100644
--- a/tez-ui2/src/main/webapp/app/adapters/rm.js
+++ b/tez-ui2/src/main/webapp/app/adapters/rm.js
@@ -20,6 +20,7 @@ import AbstractAdapter from './abstract';
export default AbstractAdapter.extend({
serverName: "rm",
+ outOfReachMessage: "Resource Manager (RM) is out of reach. Either it's down, or CORS is not enabled.",
// Any rm specific adapter changes must be added here
});
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/adapters/timeline.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/adapters/timeline.js b/tez-ui2/src/main/webapp/app/adapters/timeline.js
index 93e83cb..82faed8 100644
--- a/tez-ui2/src/main/webapp/app/adapters/timeline.js
+++ b/tez-ui2/src/main/webapp/app/adapters/timeline.js
@@ -24,6 +24,7 @@ var MoreObject = more.Object;
export default AbstractAdapter.extend({
serverName: "timeline",
+ outOfReachMessage: "Timeline server (ATS) is out of reach. Either it's down, or CORS is not enabled.",
filters: {
dagID: 'TEZ_DAG_ID',
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/components/error-bar.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/components/error-bar.js b/tez-ui2/src/main/webapp/app/components/error-bar.js
new file mode 100644
index 0000000..1086010
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/components/error-bar.js
@@ -0,0 +1,109 @@
+/**
+ * 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 DISPLAY_TIME = 30 * 1000;
+
+export default Ember.Component.extend({
+
+ error: null,
+
+ visible: false,
+ detailsAvailable: false,
+
+ classNames: ['error-bar'],
+ classNameBindings: ['visible', 'detailsAvailable'],
+
+ code: null,
+ message: null,
+ details: null,
+ stack: null,
+
+ showDetails: false,
+
+ displayTimerId: 0,
+
+ _errorObserver: Ember.observer("error", function () {
+ var error = this.get("error"),
+
+ code = Ember.get(error, "errors.0.status"),
+ title = Ember.get(error, "errors.0.title"),
+ message = error.message || "Error",
+ details = Ember.get(error, "errors.0.detail") || "",
+ stack = error.stack,
+ lineEndIndex = Math.min(message.indexOf('\n'), message.indexOf('<br'));
+
+ if(code === "0") {
+ code = "";
+ }
+
+ if(title) {
+ message += ". " + title;
+ }
+
+ if(lineEndIndex > 0) {
+ if(details) {
+ details = "\n" + details;
+ }
+ details = message.substr(lineEndIndex) + details;
+ message = message.substr(0, lineEndIndex);
+ }
+
+ if(details) {
+ details += "\n";
+ }
+
+ if(error) {
+ this.setProperties({
+ code: code,
+ message: message,
+ details: details,
+ stack: stack,
+
+ detailsAvailable: !!(details || stack),
+ visible: true
+ });
+
+ this.clearTimer();
+ this.set("displayTimerId", setTimeout(this.close.bind(this), DISPLAY_TIME));
+ }
+ else {
+ this.close();
+ }
+ }),
+
+ clearTimer: function () {
+ clearTimeout(this.get("displayTimerId"));
+ },
+ close: function () {
+ this.set("visible", false);
+ this.clearTimer();
+ },
+
+ actions: {
+ toggleDetailsDisplay: function () {
+ this.toggleProperty("showDetails");
+ this.clearTimer();
+ },
+ close: function () {
+ this.close();
+ }
+ }
+
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/controllers/application.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/controllers/application.js b/tez-ui2/src/main/webapp/app/controllers/application.js
index 24db40a..4911a16 100644
--- a/tez-ui2/src/main/webapp/app/controllers/application.js
+++ b/tez-ui2/src/main/webapp/app/controllers/application.js
@@ -25,6 +25,8 @@ const BREADCRUMB_PREFIX = [{
export default Ember.Controller.extend({
breadcrumbs: null,
+ appError: null,
+
prefixedBreadcrumbs: Ember.computed("breadcrumbs", function () {
var prefix = BREADCRUMB_PREFIX,
breadcrumbs = this.get('breadcrumbs');
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/entities/entity.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/entities/entity.js b/tez-ui2/src/main/webapp/app/entities/entity.js
index 8a10dee..6f98097 100644
--- a/tez-ui2/src/main/webapp/app/entities/entity.js
+++ b/tez-ui2/src/main/webapp/app/entities/entity.js
@@ -98,11 +98,13 @@ var Entity = Ember.Object.extend(NameMixin, {
);
needLoader.then(function (model) {
+ parentModel.refreshLoadTime();
parentModel.set(needOptions.name, model);
});
if(needOptions.silent) {
needLoader = needLoader.catch(function () {
+ parentModel.refreshLoadTime();
parentModel.set(needOptions.name, null);
});
}
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/abstract.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/abstract.js b/tez-ui2/src/main/webapp/app/routes/abstract.js
index 923ac96..39b8314 100644
--- a/tez-ui2/src/main/webapp/app/routes/abstract.js
+++ b/tez-ui2/src/main/webapp/app/routes/abstract.js
@@ -98,7 +98,8 @@ export default Ember.Route.extend(NameMixin, {
then(this.checkAndCall.bind(this, promiseId, "beforeLoad", query, options)).
then(this.checkAndCall.bind(this, promiseId, "load", query, options)).
then(this.checkAndCall.bind(this, promiseId, "afterLoad", query, options)).
- then(this.checkAndCall.bind(this, promiseId, "setValue", query, options));
+ then(this.checkAndCall.bind(this, promiseId, "setValue", query, options)).
+ catch(this.onLoadFailure.bind(this));
},
setLoading: function (/*query, options*/) {
@@ -124,6 +125,15 @@ export default Ember.Route.extend(NameMixin, {
return value;
},
+ onLoadFailure: function (error) {
+ if(error instanceof UnlinkedPromise) {
+ Ember.Logger.warn("Slow down, you are refreshing too fast!");
+ }
+ else {
+ this.send("error", error);
+ throw(error);
+ }
+ },
getLoadTime: function (value) {
if(value instanceof DS.RecordArray) {
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/am-pollster.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/am-pollster.js b/tez-ui2/src/main/webapp/app/routes/am-pollster.js
index 5907a91..6752ffd 100644
--- a/tez-ui2/src/main/webapp/app/routes/am-pollster.js
+++ b/tez-ui2/src/main/webapp/app/routes/am-pollster.js
@@ -17,6 +17,8 @@
* limitations under the License.
*/
+import Ember from 'ember';
+
import PollsterRoute from './pollster';
var MoreObject = more.Object;
@@ -45,13 +47,11 @@ export default PollsterRoute.extend({
that.reload();
}
else {
- error.message = "Application Master (AM) is out of reach. Either it's down, or CORS is not enabled for YARN ResourceManager.";
that.send("error", error);
}
}, function (error) {
- error.message = "Resource Manager (RM) is out of reach. Either it's down, or CORS is not enabled.";
that.send("error", error);
- that.reload();
+ Ember.run.later(that, "reload", this.get("polling.interval") * 3);
});
},
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/app.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/app.js b/tez-ui2/src/main/webapp/app/routes/app.js
index a60025e..395a9be 100644
--- a/tez-ui2/src/main/webapp/app/routes/app.js
+++ b/tez-ui2/src/main/webapp/app/routes/app.js
@@ -26,7 +26,8 @@ export default AbstractRoute.extend({
},
model: function (params) {
- return this.get("loader").queryRecord('app', "tez_" + this.queryFromParams(params).id);
+ return this.get("loader").queryRecord('app', "tez_" + this.queryFromParams(params).id).
+ catch(this.onLoadFailure.bind(this));
},
actions: {
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/application.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/application.js b/tez-ui2/src/main/webapp/app/routes/application.js
index 121eda2..41ea3fb 100644
--- a/tez-ui2/src/main/webapp/app/routes/application.js
+++ b/tez-ui2/src/main/webapp/app/routes/application.js
@@ -38,7 +38,7 @@ export default Ember.Route.extend({
},
error: function (error) {
- // Display error bar
+ this.set("controller.appError", error);
Ember.Logger.error(error);
},
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/attempt.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/attempt.js b/tez-ui2/src/main/webapp/app/routes/attempt.js
index 4a1ac20..3d0224f 100644
--- a/tez-ui2/src/main/webapp/app/routes/attempt.js
+++ b/tez-ui2/src/main/webapp/app/routes/attempt.js
@@ -26,7 +26,8 @@ export default AbstractRoute.extend({
},
model: function (params) {
- return this.get("loader").queryRecord('attempt', this.queryFromParams(params).id);
+ return this.get("loader").queryRecord('attempt', this.queryFromParams(params).id).
+ catch(this.onLoadFailure.bind(this));
},
actions: {
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/dag.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/dag.js b/tez-ui2/src/main/webapp/app/routes/dag.js
index 51e6ed9..13f1bc0 100644
--- a/tez-ui2/src/main/webapp/app/routes/dag.js
+++ b/tez-ui2/src/main/webapp/app/routes/dag.js
@@ -26,7 +26,8 @@ export default AbstractRoute.extend({
},
model: function (params) {
- return this.get("loader").queryRecord('dag', this.queryFromParams(params).id);
+ return this.get("loader").queryRecord('dag', this.queryFromParams(params).id).
+ catch(this.onLoadFailure.bind(this));
},
actions: {
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/dag/index/index.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/dag/index/index.js b/tez-ui2/src/main/webapp/app/routes/dag/index/index.js
index 15d485f..72d8686 100644
--- a/tez-ui2/src/main/webapp/app/routes/dag/index/index.js
+++ b/tez-ui2/src/main/webapp/app/routes/dag/index/index.js
@@ -44,8 +44,13 @@ export default MultiAmPollsterRoute.extend({
}
}),
+ updateLoadTime: function (value) {
+ return value;
+ },
+
actions: {
reload: function () {
+ this._super();
return true;
},
willTransition: function () {
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/pollster.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/pollster.js b/tez-ui2/src/main/webapp/app/routes/pollster.js
index 5a7af16..7d62c39 100644
--- a/tez-ui2/src/main/webapp/app/routes/pollster.js
+++ b/tez-ui2/src/main/webapp/app/routes/pollster.js
@@ -25,19 +25,18 @@ export default AbstractRoute.extend({
polledRecords: null,
// Must be implemented by inheriting classes
- onRecordPoll: Ember.K,
- onPollSuccess: Ember.K,
- onPollFailure: Ember.K,
+ onRecordPoll: function (val) {return val;},
+ onPollSuccess: function (val) {return val;},
+ onPollFailure: function (err) {throw(err);},
pollData: function () {
var polledRecords = this.get("polledRecords");
if(!this.get("isLoading") && polledRecords) {
polledRecords = polledRecords.map(this.onRecordPoll.bind(this));
- return Ember.RSVP.all(polledRecords).then(
- this.onPollSuccess.bind(this),
- this.onPollFailure.bind(this)
- );
+ return Ember.RSVP.all(polledRecords).
+ then(this.updateLoadTime.bind(this)).
+ then(this.onPollSuccess.bind(this), this.onPollFailure.bind(this));
}
return Ember.RSVP.reject();
},
@@ -46,6 +45,11 @@ export default AbstractRoute.extend({
return this.get("polledRecords") && this.get("loadedValue");
}),
+ updateLoadTime: function (value) {
+ this.send("setLoadTime", this.getLoadTime(value));
+ return value;
+ },
+
_canPollInit: Ember.on("init", function () {
// This sets a flag that ensures that the _canPollObserver is called whenever
// canPoll changes. By default observers on un-used computed properties
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/task.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/task.js b/tez-ui2/src/main/webapp/app/routes/task.js
index 42d9715..54d29f1 100644
--- a/tez-ui2/src/main/webapp/app/routes/task.js
+++ b/tez-ui2/src/main/webapp/app/routes/task.js
@@ -26,7 +26,8 @@ export default AbstractRoute.extend({
},
model: function (params) {
- return this.get("loader").queryRecord('task', this.queryFromParams(params).id);
+ return this.get("loader").queryRecord('task', this.queryFromParams(params).id).
+ catch(this.onLoadFailure.bind(this));
},
actions: {
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/routes/vertex.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/routes/vertex.js b/tez-ui2/src/main/webapp/app/routes/vertex.js
index 5e8ed33..6e99fd1 100644
--- a/tez-ui2/src/main/webapp/app/routes/vertex.js
+++ b/tez-ui2/src/main/webapp/app/routes/vertex.js
@@ -26,7 +26,8 @@ export default AbstractRoute.extend({
},
model: function (params) {
- return this.get("loader").queryRecord('vertex', this.queryFromParams(params).id);
+ return this.get("loader").queryRecord('vertex', this.queryFromParams(params).id).
+ catch(this.onLoadFailure.bind(this));
},
actions: {
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/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 758d1ab..cdeccd1 100644
--- a/tez-ui2/src/main/webapp/app/styles/app.less
+++ b/tez-ui2/src/main/webapp/app/styles/app.less
@@ -16,15 +16,19 @@
* limitations under the License.
*/
+// Prerequisites
@import "colors";
@import "shared";
@import "tooltip";
+// Components
@import "tab-n-refresh";
@import "dags-page-search";
+@import "table-controls";
+@import "column-selector";
+@import "error-bar";
+// Pages
@import "page-layout";
@import "details-page";
-@import "table-controls";
-@import "column-selector";
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/styles/error-bar.less
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/styles/error-bar.less b/tez-ui2/src/main/webapp/app/styles/error-bar.less
new file mode 100644
index 0000000..dec2100
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/styles/error-bar.less
@@ -0,0 +1,102 @@
+/**
+ * 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.
+ */
+
+.error-bar {
+ position: fixed;
+ z-index: 1000;
+
+ padding: 9px 30px;
+ min-height: 50px;
+ width: 100%;
+
+ bottom: -50px;
+ opacity: 0;
+ height: 50px;
+
+ &.visible {
+ bottom: -10px;
+ opacity: 1;
+ height: auto;
+ }
+
+ transition: all .2s cubic-bezier(0.175, 0.885, 0.320, 1.275);
+ transition-property: bottom, opacity, height;
+ -webkit-transition: all .2s cubic-bezier(0.175, 0.885, 0.320, 1.275);
+ -webkit-transition-property: bottom, opacity, height;
+
+ border-top: 1px @border-lite solid;
+ background-color: #F5F5DC;
+ color: @text-red;
+
+ .message, .details {
+ overflow: scroll;
+ max-height: 100px;
+
+ text-align: left;
+ }
+
+ .details {
+ display: none;
+ visibility: hidden;
+
+ margin-bottom: 10px;
+
+ border-top: 1px @border-lite solid;
+
+ .force-scrollbar;
+ white-space: pre-line;
+
+ &.visible {
+ display: block;
+ }
+ }
+
+ .close-button, .show-details {
+ position: absolute;
+ top: 12px;
+
+ color: @text-color;
+ opacity: .7;
+
+ &:hover {
+ cursor: pointer;
+ opacity: 1;
+ }
+ }
+
+ .close-button {
+ right: 30px;
+ }
+
+ .show-details {
+ right: 45px;
+ visibility: hidden;
+ }
+
+ &.details-available {
+ .message {
+ cursor: pointer;
+ }
+ .details {
+ visibility: visible;
+ }
+ .show-details {
+ visibility: visible;
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/templates/application.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/application.hbs b/tez-ui2/src/main/webapp/app/templates/application.hbs
index 16a0329..7bdc2b7 100644
--- a/tez-ui2/src/main/webapp/app/templates/application.hbs
+++ b/tez-ui2/src/main/webapp/app/templates/application.hbs
@@ -23,7 +23,6 @@
<div class="lr-margin content">
{{#link-to 'application' class="logo"}}
<img src="assets/images/logo.png" width="70px"/>
- <span>{{unbound App.env.version}}</span>
{{/link-to}}
<div class="breadcrumb-container">
@@ -64,3 +63,5 @@
</div>
{{outlet "modal"}}
+
+{{error-bar error=appError}}
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/app/templates/components/error-bar.hbs
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/app/templates/components/error-bar.hbs b/tez-ui2/src/main/webapp/app/templates/components/error-bar.hbs
new file mode 100644
index 0000000..a21bba0
--- /dev/null
+++ b/tez-ui2/src/main/webapp/app/templates/components/error-bar.hbs
@@ -0,0 +1,31 @@
+{{!
+ * 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="message" {{action "toggleDetailsDisplay"}}>
+ <i class="fa fa-exclamation-circle"></i>
+ {{#if code}}
+ <b>{{code}}</b> :
+ {{/if}}
+ {{message}}
+ <i class="show-details fa {{if showDetails 'fa-minus-circle' 'fa-plus-circle'}}"></i>
+</div>
+<div class="details {{if showDetails "visible"}}">{{{details}}}{{#if stack}}<b>Stack:</b>
+ {{stack}}
+ {{/if}}
+</div>
+<i class="close-button fa fa-arrow-circle-down" {{action "close"}}></i>
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/tests/integration/components/error-bar-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/integration/components/error-bar-test.js b/tez-ui2/src/main/webapp/tests/integration/components/error-bar-test.js
new file mode 100644
index 0000000..10c6c7d
--- /dev/null
+++ b/tez-ui2/src/main/webapp/tests/integration/components/error-bar-test.js
@@ -0,0 +1,43 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { moduleForComponent, test } from 'ember-qunit';
+import hbs from 'htmlbars-inline-precompile';
+
+moduleForComponent('error-bar', 'Integration | Component | error bar', {
+ integration: true
+});
+
+test('Basic creation test', function(assert) {
+
+ // Set any properties with this.set('myProperty', 'value');
+ // Handle any actions with this.on('myAction', function(val) { ... });" + EOL + EOL +
+
+ this.render(hbs`{{error-bar}}`);
+
+ assert.equal(this.$().text().trim(), '');
+
+ // Template block usage:" + EOL +
+ this.render(hbs`
+ {{#error-bar}}
+ template block text
+ {{/error-bar}}
+ `);
+
+ assert.equal(this.$().text().trim(), '');
+});
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js b/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js
index fb0bd8a..9e2550d 100644
--- a/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js
+++ b/tez-ui2/src/main/webapp/tests/unit/entities/entity-test.js
@@ -78,6 +78,7 @@ test('loadAllNeeds basic test', function(assert) {
let adapter = this.subject(),
loader,
testModel = Ember.Object.create({
+ refreshLoadTime: Ember.K,
needs: {
app: "appID",
foo: "fooID"
@@ -115,6 +116,7 @@ test('loadAllNeeds silent=false test', function(assert) {
let adapter = this.subject(),
loader,
testModel = Ember.Object.create({
+ refreshLoadTime: Ember.K,
needs: {
app: {
idKey: "appID",
@@ -142,6 +144,7 @@ test('loadAllNeeds silent=true test', function(assert) {
let adapter = this.subject(),
loader,
testModel = Ember.Object.create({
+ refreshLoadTime: Ember.K,
needs: {
app: {
idKey: "appID",
http://git-wip-us.apache.org/repos/asf/tez/blob/6d4bb2c6/tez-ui2/src/main/webapp/tests/unit/routes/abstract-test.js
----------------------------------------------------------------------
diff --git a/tez-ui2/src/main/webapp/tests/unit/routes/abstract-test.js b/tez-ui2/src/main/webapp/tests/unit/routes/abstract-test.js
index 202e889..9ed3452 100644
--- a/tez-ui2/src/main/webapp/tests/unit/routes/abstract-test.js
+++ b/tez-ui2/src/main/webapp/tests/unit/routes/abstract-test.js
@@ -18,8 +18,6 @@
import Ember from 'ember';
-import UnlinkedPromise from '../../../errors/unlinked-promise';
-
import { moduleFor, test } from 'ember-qunit';
moduleFor('route:abstract', 'Unit | Route | abstract', {
@@ -174,8 +172,8 @@ test('loadData test - ID change check with exception throw', function(assert) {
route.loadData().then(function () {
assert.notOk("Shouldn't be called");
- }).catch(function (e) {
- assert.ok(e instanceof UnlinkedPromise, "Exception thrown");
+ }).catch(function () {
+ assert.ok(true, "Exception thrown");
});
});