Repository: tez
Updated Branches:
  refs/heads/master 1264d5d01 -> 2c22e23a7


TEZ-3288. Tez UI: Display more details in the error bar (sree)


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

Branch: refs/heads/master
Commit: 2c22e23a738a7764aa8d53ca7e2bcba7d7053337
Parents: 1264d5d
Author: Sreenath Somarajapuram <s...@apache.org>
Authored: Sat Jun 25 17:49:55 2016 +0530
Committer: Sreenath Somarajapuram <s...@apache.org>
Committed: Sat Jun 25 17:49:55 2016 +0530

----------------------------------------------------------------------
 CHANGES.txt                                     |   1 +
 tez-ui/src/main/webapp/app/adapters/abstract.js |  67 ++++++--
 tez-ui/src/main/webapp/app/adapters/loader.js   |   3 +-
 .../src/main/webapp/app/components/error-bar.js |  51 +------
 .../src/main/webapp/app/initializers/jquery.js  |   4 -
 .../src/main/webapp/app/styles/error-bar.less   |  17 ++-
 .../app/templates/components/error-bar.hbs      |  18 ++-
 tez-ui/src/main/webapp/package.json             |   2 +-
 .../integration/components/error-bar-test.js    |  86 ++++++++++-
 .../webapp/tests/unit/adapters/abstract-test.js | 151 +++++++++++++++++++
 .../webapp/tests/unit/adapters/loader-test.js   |   2 +
 11 files changed, 328 insertions(+), 74 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index bb130ef..640d957 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -58,6 +58,7 @@ ALL CHANGES:
   TEZ-3281. Tez UI: Swimlane improvements
   TEZ-3264. Tez UI: UI discrepancies
   TEZ-3292. Tez UI: UTs breaking with timezone change
+  TEZ-3288. Tez UI: Display more details in the error bar
 
 Release 0.8.4: Unreleased
 

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/app/adapters/abstract.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/adapters/abstract.js 
b/tez-ui/src/main/webapp/app/adapters/abstract.js
index 121d4ee..9a7dcae 100644
--- a/tez-ui/src/main/webapp/app/adapters/abstract.js
+++ b/tez-ui/src/main/webapp/app/adapters/abstract.js
@@ -53,18 +53,63 @@ export default LoaderAdapter.extend({
     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"));
+  normalizeErrorResponse: function (status, headers, payload) {
+    var title;
+    switch(typeof payload) {
+      case "object":
+        title = payload.message;
+      break;
+      case "string":
+        let html = Ember.$(payload.bold());
+        html.find('script').remove();
+        html.find('style').remove();
+        payload = html.text().trim();
+      break;
     }
 
-    return response;
+    return [{
+      title: title,
+      status: status,
+      headers: headers,
+      detail: payload
+    }];
+  },
+
+  _loaderAjax: function (url, queryParams, namespace) {
+    var requestInfo = {
+          adapterName: this.get("name"),
+          url: url
+        },
+        that = this;
+
+    return this._super(url, queryParams, namespace).catch(function (error) {
+      var message = `${error.message} »`,
+          status = Ember.get(error, "errors.0.status");
+
+      if(status === 0) {
+        let outOfReachMessage = that.get("outOfReachMessage");
+        message = `${message} ${outOfReachMessage}`;
+      }
+      else {
+        let title = Ember.get(error, "errors.0.title") || `Error accessing 
${url}`;
+        message = `${message} ${status}: ${title}`;
+      }
+
+      requestInfo.responseHeaders = Ember.get(error, "errors.0.headers");
+      if(queryParams) {
+        requestInfo.queryParams = queryParams;
+      }
+      if(namespace) {
+        requestInfo.namespace = namespace;
+      }
+
+      Ember.setProperties(error, {
+        message: message,
+        details: Ember.get(error, "errors.0.detail"),
+        requestInfo: requestInfo
+      });
+
+      throw(error);
+    });
   }
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/app/adapters/loader.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/adapters/loader.js 
b/tez-ui/src/main/webapp/app/adapters/loader.js
index f63bd07..5000bea 100644
--- a/tez-ui/src/main/webapp/app/adapters/loader.js
+++ b/tez-ui/src/main/webapp/app/adapters/loader.js
@@ -18,10 +18,11 @@
  */
 
 import DS from 'ember-data';
+import NameMixin from '../mixins/name';
 
 var MoreString = more.String;
 
-export default DS.RESTAdapter.extend({
+export default DS.RESTAdapter.extend(NameMixin, {
   _isLoader: true,
 
   buildURL: function(modelName, id, snapshot, requestType, query, params) {

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/app/components/error-bar.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/components/error-bar.js 
b/tez-ui/src/main/webapp/app/components/error-bar.js
index 1086010..d562614 100644
--- a/tez-ui/src/main/webapp/app/components/error-bar.js
+++ b/tez-ui/src/main/webapp/app/components/error-bar.js
@@ -26,57 +26,21 @@ export default Ember.Component.extend({
 
   visible: false,
   detailsAvailable: false,
+  showDetails: false,
+  displayTimerId: 0,
 
   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";
-    }
+  _errorObserver: Ember.on("init", Ember.observer("error", function () {
+    var error = this.get("error");
 
     if(error) {
       this.setProperties({
-        code: code,
-        message: message,
-        details: details,
-        stack: stack,
-
-        detailsAvailable: !!(details || stack),
+        message: error.message || "Error",
+        detailsAvailable: !!(error.details || error.requestInfo || 
error.stack),
         visible: true
       });
 
@@ -86,7 +50,7 @@ export default Ember.Component.extend({
     else {
       this.close();
     }
-  }),
+  })),
 
   clearTimer: function () {
     clearTimeout(this.get("displayTimerId"));
@@ -105,5 +69,4 @@ export default Ember.Component.extend({
       this.close();
     }
   }
-
 });

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/app/initializers/jquery.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/initializers/jquery.js 
b/tez-ui/src/main/webapp/app/initializers/jquery.js
index 2c34b1d..37ebc4d 100644
--- a/tez-ui/src/main/webapp/app/initializers/jquery.js
+++ b/tez-ui/src/main/webapp/app/initializers/jquery.js
@@ -24,10 +24,6 @@ export function initialize(/* application */) {
     tooltipClass: 'generic-tooltip'
   });
 
-  Ember.$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
-    jqXHR.requestOptions = originalOptions;
-  });
-
   Ember.$.ajaxSetup({
     cache: false
   });

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/app/styles/error-bar.less
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/styles/error-bar.less 
b/tez-ui/src/main/webapp/app/styles/error-bar.less
index dec2100..56d2b88 100644
--- a/tez-ui/src/main/webapp/app/styles/error-bar.less
+++ b/tez-ui/src/main/webapp/app/styles/error-bar.less
@@ -44,22 +44,31 @@
   color: @text-red;
 
   .message, .details {
-    overflow: scroll;
-    max-height: 100px;
-
+    max-height: 150px;
     text-align: left;
   }
 
+  .message {
+    overflow: hidden;
+    white-space: nowrap;
+    text-overflow: ellipsis;
+    margin-right: 30px;
+  }
+
   .details {
     display: none;
     visibility: hidden;
+    overflow: scroll;
 
     margin-bottom: 10px;
 
     border-top: 1px @border-lite solid;
 
     .force-scrollbar;
-    white-space: pre-line;
+
+    p {
+      white-space: pre-wrap;
+    }
 
     &.visible {
       display: block;

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/app/templates/components/error-bar.hbs
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/app/templates/components/error-bar.hbs 
b/tez-ui/src/main/webapp/app/templates/components/error-bar.hbs
index a21bba0..fe5d44d 100644
--- a/tez-ui/src/main/webapp/app/templates/components/error-bar.hbs
+++ b/tez-ui/src/main/webapp/app/templates/components/error-bar.hbs
@@ -18,14 +18,22 @@
 
 <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}}
+
+<div class="details {{if showDetails "visible"}}">
+  {{#if error.details}}
+    <b>Details:</b>
+    <p>{{txt error.details type="json"}}</p>
+  {{/if}}
+  {{#if error.requestInfo}}
+    <b>Request:</b>
+    <p>{{txt error.requestInfo type="json"}}</p>
+  {{/if}}
+  {{#if error.stack}}
+    <b>Stack:</b>
+    <p>{{error.stack}}</p>
   {{/if}}
 </div>
 <i class="close-button fa fa-arrow-circle-down" {{action "close"}}></i>

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/package.json
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/package.json 
b/tez-ui/src/main/webapp/package.json
index 15a77e4..e5c3279 100644
--- a/tez-ui/src/main/webapp/package.json
+++ b/tez-ui/src/main/webapp/package.json
@@ -57,7 +57,7 @@
     "phantomjs": "1.9.19"
   },
   "dependencies": {
-    "em-helpers": "0.5.10",
+    "em-helpers": "0.5.13",
     "em-table": "0.3.14",
     "em-tgraph": "0.0.5"
   }

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/tests/integration/components/error-bar-test.js
----------------------------------------------------------------------
diff --git 
a/tez-ui/src/main/webapp/tests/integration/components/error-bar-test.js 
b/tez-ui/src/main/webapp/tests/integration/components/error-bar-test.js
index 10c6c7d..f736b45 100644
--- a/tez-ui/src/main/webapp/tests/integration/components/error-bar-test.js
+++ b/tez-ui/src/main/webapp/tests/integration/components/error-bar-test.js
@@ -19,15 +19,13 @@
 import { moduleForComponent, test } from 'ember-qunit';
 import hbs from 'htmlbars-inline-precompile';
 
+import wait from 'ember-test-helpers/wait';
+
 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(), '');
@@ -41,3 +39,83 @@ test('Basic creation test', function(assert) {
 
   assert.equal(this.$().text().trim(), '');
 });
+
+test('Plain Object test', function(assert) {
+  Function.prototype.bind = function () {};
+
+  this.set("error", {});
+  this.render(hbs`{{error-bar error=error}}`);
+
+  return wait().then(() => {
+    assert.equal(this.$().text().trim(), 'Error');
+  });
+});
+
+test('Message test', function(assert) {
+  var testMessage = "Test Message";
+
+  Function.prototype.bind = function () {};
+
+  this.set("error", {
+    message: testMessage
+  });
+  this.render(hbs`{{error-bar error=error}}`);
+
+  return wait().then(() => {
+    assert.equal(this.$().text().trim(), testMessage);
+  });
+});
+
+test('details test', function(assert) {
+  var testMessage = "Test Message",
+      testDetails = "details";
+
+  Function.prototype.bind = function () {};
+
+  this.set("error", {
+    message: testMessage,
+    details: testDetails
+  });
+  this.render(hbs`{{error-bar error=error}}`);
+
+  return wait().then(() => {
+    assert.equal(this.$(".message").text().trim(), testMessage);
+    assert.equal(this.$(".details p").text().trim(), testDetails);
+  });
+});
+
+test('requestInfo test', function(assert) {
+  var testMessage = "Test Message",
+      testInfo = "info";
+
+  Function.prototype.bind = function () {};
+
+  this.set("error", {
+    message: testMessage,
+    requestInfo: testInfo
+  });
+  this.render(hbs`{{error-bar error=error}}`);
+
+  return wait().then(() => {
+    assert.equal(this.$(".message").text().trim(), testMessage);
+    assert.equal(this.$(".details p").text().trim(), testInfo);
+  });
+});
+
+test('stack test', function(assert) {
+  var testMessage = "Test Message",
+      testStack = "stack";
+
+  Function.prototype.bind = function () {};
+
+  this.set("error", {
+    message: testMessage,
+    stack: testStack
+  });
+  this.render(hbs`{{error-bar error=error}}`);
+
+  return wait().then(() => {
+    assert.equal(this.$(".message").text().trim(), testMessage);
+    assert.equal(this.$(".details p").text().trim(), testStack);
+  });
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/tests/unit/adapters/abstract-test.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/tests/unit/adapters/abstract-test.js 
b/tez-ui/src/main/webapp/tests/unit/adapters/abstract-test.js
index 5ff39e7..24ba624 100644
--- a/tez-ui/src/main/webapp/tests/unit/adapters/abstract-test.js
+++ b/tez-ui/src/main/webapp/tests/unit/adapters/abstract-test.js
@@ -16,6 +16,8 @@
  * limitations under the License.
  */
 
+import Ember from 'ember';
+
 import { moduleFor, test } from 'ember-qunit';
 
 moduleFor('adapter:abstract', 'Unit | Adapter | abstract', {
@@ -35,6 +37,9 @@ test('Basic creation test', function(assert) {
 
   assert.ok(adapter.ajaxOptions);
   assert.ok(adapter.pathForType);
+
+  assert.ok(adapter.normalizeErrorResponse);
+  assert.ok(adapter._loaderAjax);
 });
 
 test('host, namespace & pathTypeHash test', function(assert) {
@@ -108,3 +113,149 @@ test('pathForType test', function(assert) {
     adapter.pathForType("noType");
   });
 });
+
+test('normalizeErrorResponse test', function(assert) {
+  let adapter = this.subject(),
+      status = "200",
+      testTitle = "title",
+      strPayload = "StringPayload",
+      objPayload = {x: 1, message: testTitle},
+      testHeaders = {},
+      response;
+
+  response = adapter.normalizeErrorResponse(status, testHeaders, strPayload);
+  assert.equal(response[0].title, undefined);
+  assert.equal(response[0].status, status);
+  assert.equal(response[0].detail, strPayload);
+  assert.equal(response[0].headers, testHeaders);
+
+  response = adapter.normalizeErrorResponse(status, testHeaders, objPayload);
+  assert.equal(response[0].title, testTitle);
+  assert.equal(response[0].status, status);
+  assert.deepEqual(response[0].detail, objPayload);
+  assert.equal(response[0].headers, testHeaders);
+});
+
+test('normalizeErrorResponse html payload test', function(assert) {
+  let adapter = this.subject(),
+      status = "200",
+      htmlPayload = "StringPayload <b>boldText</b> <script>scriptText</script> 
<style>styleText</style>",
+      testHeaders = {},
+      response;
+
+  response = adapter.normalizeErrorResponse(status, testHeaders, htmlPayload);
+  assert.equal(response[0].detail, "StringPayload boldText");
+});
+
+test('_loaderAjax resolve test', function(assert) {
+  let result = {},
+      adapter = this.subject({
+        ajax: function () {
+          assert.ok(1);
+          return Ember.RSVP.resolve(result);
+        }
+      });
+
+  assert.expect(1 + 1);
+
+  adapter._loaderAjax().then(function (val) {
+    assert.equal(val.data, result);
+  });
+});
+
+test('_loaderAjax reject, without title test', function(assert) {
+  let errorInfo = {
+        status: "500",
+        detail: "testDetails"
+      },
+      msg = "Msg",
+      testUrl = "http://foo.bar";,
+      testQuery = {},
+      testNS = "namespace",
+      adapter = this.subject({
+        outOfReachMessage: "OutOfReach",
+        ajax: function () {
+          assert.ok(1);
+          return Ember.RSVP.reject({
+            message: msg,
+            errors:[errorInfo]
+          });
+        }
+      });
+
+  assert.expect(1 + 7);
+
+  adapter._loaderAjax(testUrl, testQuery, testNS).catch(function (val) {
+    assert.equal(val.message, `${msg} » ${errorInfo.status}: Error accessing 
${testUrl}`);
+    assert.equal(val.details, errorInfo.detail);
+    assert.equal(val.requestInfo.adapterName, "abstract");
+    assert.equal(val.requestInfo.url, testUrl);
+
+    assert.equal(val.requestInfo.queryParams, testQuery);
+    assert.equal(val.requestInfo.namespace, testNS);
+
+    assert.ok(val.requestInfo.hasOwnProperty("responseHeaders"));
+  });
+});
+
+test('_loaderAjax reject, with title test', function(assert) {
+  let errorInfo = {
+        status: "500",
+        title: "Server Error",
+        detail: "testDetails"
+      },
+      msg = "Msg",
+      testUrl = "url",
+      adapter = this.subject({
+        outOfReachMessage: "OutOfReach",
+        ajax: function () {
+          assert.ok(1);
+          return Ember.RSVP.reject({
+            message: msg,
+            errors:[errorInfo]
+          });
+        }
+      });
+
+  assert.expect(1 + 5);
+
+  adapter._loaderAjax(testUrl).catch(function (val) {
+    assert.equal(val.message, `${msg} » ${errorInfo.status}: 
${errorInfo.title}`);
+    assert.equal(val.details, errorInfo.detail);
+    assert.equal(val.requestInfo.adapterName, "abstract");
+    assert.equal(val.requestInfo.url, testUrl);
+
+    assert.ok(val.requestInfo.hasOwnProperty("responseHeaders"));
+  });
+});
+
+test('_loaderAjax reject, status 0 test', function(assert) {
+  let errorInfo = {
+        status: 0,
+        title: "Server Error",
+        detail: "testDetails"
+      },
+      msg = "Msg",
+      testUrl = "url",
+      adapter = this.subject({
+        outOfReachMessage: "OutOfReach",
+        ajax: function () {
+          assert.ok(1);
+          return Ember.RSVP.reject({
+            message: msg,
+            errors:[errorInfo]
+          });
+        }
+      });
+
+  assert.expect(1 + 5);
+
+  adapter._loaderAjax(testUrl).catch(function (val) {
+    assert.equal(val.message, `${msg} » ${adapter.outOfReachMessage}`);
+    assert.equal(val.details, errorInfo.detail);
+    assert.equal(val.requestInfo.adapterName, "abstract");
+    assert.equal(val.requestInfo.url, testUrl);
+
+    assert.ok(val.requestInfo.hasOwnProperty("responseHeaders"));
+  });
+});

http://git-wip-us.apache.org/repos/asf/tez/blob/2c22e23a/tez-ui/src/main/webapp/tests/unit/adapters/loader-test.js
----------------------------------------------------------------------
diff --git a/tez-ui/src/main/webapp/tests/unit/adapters/loader-test.js 
b/tez-ui/src/main/webapp/tests/unit/adapters/loader-test.js
index 7b4a2df..e8e0428 100644
--- a/tez-ui/src/main/webapp/tests/unit/adapters/loader-test.js
+++ b/tez-ui/src/main/webapp/tests/unit/adapters/loader-test.js
@@ -34,6 +34,8 @@ test('Basic creation', function(assert) {
   assert.ok(adapter._loaderAjax);
   assert.ok(adapter.queryRecord);
   assert.ok(adapter.query);
+
+  assert.equal(adapter.get("name"), "loader");
 });
 
 test('buildURL test', function(assert) {

Reply via email to