You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by yu...@apache.org on 2015/09/03 06:35:13 UTC

ambari git commit: AMBARI-12615. Add Data Visualization to Hive View. (Vivek Ratnavel Subramanian)

Repository: ambari
Updated Branches:
  refs/heads/branch-2.1 77529726a -> e54a453cd


AMBARI-12615. Add Data Visualization to Hive View. (Vivek Ratnavel Subramanian)


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

Branch: refs/heads/branch-2.1
Commit: e54a453cdfa4baff374a548236ff777b8375f3ee
Parents: 7752972
Author: Yusaku Sako <yu...@hortonworks.com>
Authored: Wed Aug 5 23:27:52 2015 -0700
Committer: Yusaku Sako <yu...@hortonworks.com>
Committed: Wed Sep 2 21:34:46 2015 -0700

----------------------------------------------------------------------
 ambari-web/app/views/main/views/details.js      |  4 +-
 contrib/views/hive/pom.xml                      | 11 ++-
 .../resources/browser/HiveBrowserService.java   | 41 +++++-----
 .../view/hive/resources/jobs/JobService.java    |  3 +-
 .../jobs/ResultsPaginationController.java       | 39 +++++++---
 .../src/main/resources/ui/hive-web/.jshintrc    |  3 +-
 .../app/components/visualization-tabs-widget.js | 56 ++++++++++++++
 .../ui/hive-web/app/controllers/query-tabs.js   | 10 +++
 .../app/controllers/visualization-ui.js         | 79 ++++++++++++++++++++
 .../ui/hive-web/app/initializers/i18n.js        |  4 +-
 .../components/visualization-tabs-widget.hbs    | 27 +++++++
 .../hive-web/app/templates/visualization-ui.hbs | 32 ++++++++
 .../ui/hive-web/app/utils/constants.js          |  7 +-
 .../ui/hive-web/app/views/visualization-ui.js   | 37 +++++++++
 .../src/main/resources/ui/hive-web/bower.json   |  4 +-
 15 files changed, 319 insertions(+), 38 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/ambari-web/app/views/main/views/details.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/views/details.js b/ambari-web/app/views/main/views/details.js
index e90cb20..956ac71 100644
--- a/ambari-web/app/views/main/views/details.js
+++ b/ambari-web/app/views/main/views/details.js
@@ -24,9 +24,9 @@ App.MainViewsDetailsView = Em.View.extend({
 
   tagName: "iframe",
   classNames: ["views_sizes"],
-  attributeBindings: ['src','seamless'],
+  attributeBindings: ['src','seamless','allowfullscreen'],
   seamless: "seamless",
-
+  allowfullscreen: "true",
   interval: null,
 
   /**

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/pom.xml
----------------------------------------------------------------------
diff --git a/contrib/views/hive/pom.xml b/contrib/views/hive/pom.xml
index dc0d5f6..455ab32 100644
--- a/contrib/views/hive/pom.xml
+++ b/contrib/views/hive/pom.xml
@@ -240,7 +240,6 @@
           </execution>
         </executions>
       </plugin>
-
       <plugin>
         <artifactId>exec-maven-plugin</artifactId>
         <groupId>org.codehaus.mojo</groupId>
@@ -318,6 +317,16 @@
         <filtering>false</filtering>
       </resource>
       <resource>
+        <directory>src/main/resources/ui/hive-web/bower_components/polestar</directory>
+        <filtering>false</filtering>
+        <targetPath>polestar</targetPath>
+      </resource>
+      <resource>
+        <directory>src/main/resources/ui/hive-web/bower_components/voyager</directory>
+        <filtering>false</filtering>
+        <targetPath>voyager</targetPath>
+      </resource>
+      <resource>
         <targetPath>WEB-INF/lib</targetPath>
         <filtering>false</filtering>
         <directory>target/lib</directory>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java
index a0d44f5..55919a7 100644
--- a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/browser/HiveBrowserService.java
@@ -113,6 +113,7 @@ public class HiveBrowserService {
                             @QueryParam("first") String fromBeginning,
                             @QueryParam("count") Integer count,
                             @QueryParam("searchId") String searchId,
+                            @QueryParam("format") String format,
                             @QueryParam("columns") final String requestedColumns) {
     if (like == null)
       like = "*";
@@ -122,14 +123,14 @@ public class HiveBrowserService {
     try {
       final String finalLike = like;
       return ResultsPaginationController.getInstance(context)
-          .request("databases", searchId, false, fromBeginning, count,
-              new Callable<Cursor>() {
-                @Override
-                public Cursor call() throws Exception {
-                  TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
-                  return getConnectionFactory().getHiveConnection().ddl().getDBListCursor(session, finalLike);
-                }
-              }).build();
+          .request("databases", searchId, false, fromBeginning, count, format,
+                  new Callable<Cursor>() {
+                    @Override
+                    public Cursor call() throws Exception {
+                      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
+                      return getConnectionFactory().getHiveConnection().ddl().getDBListCursor(session, finalLike);
+                    }
+                  }).build();
     } catch (WebApplicationException ex) {
       throw ex;
     } catch (IllegalArgumentException ex) {
@@ -182,6 +183,7 @@ public class HiveBrowserService {
                                    @QueryParam("first") String fromBeginning,
                                    @QueryParam("count") Integer count,
                                    @QueryParam("searchId") String searchId,
+                                   @QueryParam("format") String format,
                                    @QueryParam("columns") final String requestedColumns) {
     if (like == null)
       like = "*";
@@ -191,16 +193,16 @@ public class HiveBrowserService {
     try {
       final String finalLike = like;
       return ResultsPaginationController.getInstance(context)
-          .request(db + ":tables", searchId, false, fromBeginning, count,
-              new Callable<Cursor>() {
-                @Override
-                public Cursor call() throws Exception {
-                  TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
-                  Cursor cursor = getConnectionFactory().getHiveConnection().ddl().getTableListCursor(session, db, finalLike);
-                  cursor.selectColumns(requestedColumns);
-                  return cursor;
-                }
-              }).build();
+          .request(db + ":tables", searchId, false, fromBeginning, count, format,
+                  new Callable<Cursor>() {
+                    @Override
+                    public Cursor call() throws Exception {
+                      TSessionHandle session = getConnectionFactory().getHiveConnection().getOrCreateSessionByTag("DDL");
+                      Cursor cursor = getConnectionFactory().getHiveConnection().ddl().getTableListCursor(session, db, finalLike);
+                      cursor.selectColumns(requestedColumns);
+                      return cursor;
+                    }
+                  }).build();
     } catch (WebApplicationException ex) {
       throw ex;
     } catch (IllegalArgumentException ex) {
@@ -253,11 +255,12 @@ public class HiveBrowserService {
                                          @QueryParam("first") String fromBeginning,
                                          @QueryParam("searchId") String searchId,
                                          @QueryParam("count") Integer count,
+                                         @QueryParam("format") String format,
                                          @QueryParam("columns") final String requestedColumns) {
     String curl = null;
     try {
       return ResultsPaginationController.getInstance(context)
-          .request(db + ":tables:" + table + ":columns", searchId, false, fromBeginning, count,
+          .request(db + ":tables:" + table + ":columns", searchId, false, fromBeginning, count, format,
               new Callable<Cursor>() {
                 @Override
                 public Cursor call() throws Exception {

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java
index 526f13f..ad46e33 100644
--- a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/JobService.java
@@ -269,6 +269,7 @@ public class JobService extends BaseService {
                              @QueryParam("first") String fromBeginning,
                              @QueryParam("count") Integer count,
                              @QueryParam("searchId") String searchId,
+                             @QueryParam("format") String format,
                              @QueryParam("columns") final String requestedColumns) {
     try {
       final JobController jobController = getResourceManager().readController(jobId);
@@ -277,7 +278,7 @@ public class JobService extends BaseService {
       }
 
       return ResultsPaginationController.getInstance(context)
-           .request(jobId, searchId, true, fromBeginning, count,
+           .request(jobId, searchId, true, fromBeginning, count, format,
                new Callable<Cursor>() {
                  @Override
                  public Cursor call() throws Exception {

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.java
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.java b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.java
index 18152ad..735e63d 100644
--- a/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.java
+++ b/contrib/views/hive/src/main/java/org/apache/ambari/view/hive/resources/jobs/ResultsPaginationController.java
@@ -28,10 +28,13 @@ import org.apache.ambari.view.hive.utils.ServiceFormattedException;
 import org.apache.commons.collections4.map.PassiveExpiringMap;
 
 import javax.ws.rs.core.Response;
+import java.lang.Object;
+import java.lang.String;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.List;
 import java.util.concurrent.Callable;
 
 /**
@@ -110,7 +113,7 @@ public class ResultsPaginationController {
     return getResultsCache().get(key);
   }
 
-  public Response.ResponseBuilder request(String key, String searchId, boolean canExpire, String fromBeginning, Integer count, Callable<Cursor> makeResultsSet) throws HiveClientException {
+  public Response.ResponseBuilder request(String key, String searchId, boolean canExpire, String fromBeginning, Integer count, String format, Callable<Cursor> makeResultsSet) throws HiveClientException {
     if (searchId == null)
       searchId = DEFAULT_SEARCH_ID;
     key = key + "?" + searchId;
@@ -123,17 +126,33 @@ public class ResultsPaginationController {
     if (count == null)
       count = DEFAULT_FETCH_COUNT;
 
-    ResultsResponse resultsResponse = new ResultsResponse();
-    resultsResponse.setSchema(resultSet.getSchema());
+    ArrayList<ColumnDescription> schema = resultSet.getSchema();
     ArrayList<Object[]> rows = new ArrayList<Object[]>(count);
     int read = resultSet.readRaw(rows, count);
-    resultsResponse.setRows(rows);
-    resultsResponse.setReadCount(read);
-    resultsResponse.setHasNext(resultSet.hasNext());
-//      resultsResponse.setSize(resultSet.size());
-    resultsResponse.setOffset(resultSet.getOffset());
-    resultsResponse.setHasResults(true);
-    return Response.ok(resultsResponse);
+    if(format != null && format.equalsIgnoreCase("d3")) {
+      List<Map<String,Object>> results = new ArrayList<Map<String,Object>>();
+      for(int i=0; i<rows.size(); i++) {
+        Object[] row = rows.get(i);
+        Map<String, Object> keyValue = new HashMap<String, Object>(row.length);
+        for(int j=0; j<row.length; j++) {
+          //Replace dots in schema with underscore
+          String schemaName = schema.get(j).getName();
+          keyValue.put(schemaName.replace('.','_'), row[j]);
+        }
+        results.add(keyValue);
+      }
+      return Response.ok(results);
+    } else {
+      ResultsResponse resultsResponse = new ResultsResponse();
+      resultsResponse.setSchema(schema);
+      resultsResponse.setRows(rows);
+      resultsResponse.setReadCount(read);
+      resultsResponse.setHasNext(resultSet.hasNext());
+      //      resultsResponse.setSize(resultSet.size());
+      resultsResponse.setOffset(resultSet.getOffset());
+      resultsResponse.setHasResults(true);
+      return Response.ok(resultsResponse);
+    }
   }
 
   public static Response.ResponseBuilder emptyResponse() {

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc b/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc
index c1fe863..0195538 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/.jshintrc
@@ -2,7 +2,8 @@
   "predef": [
     "document",
     "window",
-    "-Promise"
+    "-Promise",
+    "d3"
   ],
   "browser" : true,
   "boss" : true,

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/app/components/visualization-tabs-widget.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/components/visualization-tabs-widget.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/visualization-tabs-widget.js
new file mode 100644
index 0000000..4980b7a
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/components/visualization-tabs-widget.js
@@ -0,0 +1,56 @@
+/**
+ * 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({
+  tagName: 'tabs',
+
+  didInsertElement: function () {
+    var tabToActivate,
+        tabs = this.get('tabs');
+
+    if (tabs.get('length')) {
+      tabToActivate = tabs.find(function (tab) {
+        return tab.get('active');
+      });
+
+      if (tabToActivate) {
+        this.set('selectedTab', tabToActivate);
+      } else {
+        this.set('selectedTab', tabs.objectAt(0));
+      }
+    }
+  },
+
+  activateTab: function () {
+    var selectedTab = this.get('selectedTab');
+
+    selectedTab.set('active', true);
+
+    this.get('tabs').without(selectedTab).forEach(function (tab) {
+      tab.set('active', false);
+    });
+  }.observes('selectedTab'),
+
+  actions: {
+    selectTab: function (tab) {
+      this.set('selectedTab', tab);
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/query-tabs.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
index 4f5176c..12b9110 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/query-tabs.js
@@ -41,6 +41,16 @@ export default Ember.Controller.extend({
       tooltip: Ember.I18n.t('tooltips.settings')
     }),
     Ember.Object.create({
+      iconClass: 'fa-area-chart',
+      id: 'visualization-icon',
+      action: 'toggleOverlay',
+      tooltip: Ember.I18n.t('tooltips.visualization'),
+      into: 'index',
+      outlet: 'overlay',
+      template: 'visualization-ui',
+      onTabOpen: 'onTabOpen'
+    }),
+    Ember.Object.create({
       iconClass: 'fa-link',
       id: 'visual-explain-icon',
       action: 'toggleOverlay',

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
new file mode 100644
index 0000000..3376a03
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/controllers/visualization-ui.js
@@ -0,0 +1,79 @@
+/**
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+import Ember from 'ember';
+import constants from 'hive/utils/constants';
+
+export default Ember.Controller.extend({
+
+  needs: [ constants.namingConventions.index,
+            constants.namingConventions.openQueries,
+            constants.namingConventions.jobResults
+          ],
+  index         : Ember.computed.alias('controllers.' + constants.namingConventions.index),
+  openQueries   : Ember.computed.alias('controllers.' + constants.namingConventions.openQueries),
+  results   : Ember.computed.alias('controllers.' + constants.namingConventions.jobResults),
+
+  polestarUrl: '',
+  voyagerUrl: '',
+  polestarPath: 'polestar/#/',
+  voyagerPath: 'voyager/#/',
+
+  visualizationTabs: function () {
+    return [
+      Ember.Object.create({
+        name: 'Data Explorer',
+        id: 'data_explorer',
+        url: this.get('voyagerUrl')
+      }),
+      Ember.Object.create({
+        name: 'Advanced Visualization',
+        id: 'visualization',
+        url: this.get('polestarUrl')
+      })
+    ]
+  }.property('polestarUrl', 'voyagerUrl'),
+
+  alterIframe: function () {
+    Ember.$("#visualization_frame").height(Ember.$("#visualization").height());
+  },
+
+  actions: {
+    onTabOpen: function () {
+      var self = this;
+      var model = this.get('index.model');
+      if (model) {
+        var existingJob = this.get('results').get('cachedResults').findBy('id', model.get('id'));
+        var url = this.container.lookup('adapter:application').buildURL();
+        url += '/' + constants.namingConventions.jobs + '/' + model.get('id') + '/results?&first=true';
+        url += '&count='+constants.visualizationRowCount+'&job_id='+model.get('id');
+        if (existingJob) {
+          this.set("error", null);
+          var id = model.get('id');
+          this.set("polestarUrl", this.get('polestarPath') + "?url=" + url);
+          this.set("voyagerUrl", this.get('voyagerPath') + "?url=" + url);
+          Ember.run.scheduleOnce('afterRender', this, function(){
+            self.alterIframe();
+          });
+        } else {
+          this.set("error", "No visualization available. Please execute a query and wait for the results to visualize data.");
+        }
+      }
+    }
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
index 1ce3d9d..8f9f72d 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/initializers/i18n.js
@@ -38,6 +38,7 @@ TRANSLATIONS = {
     settings: 'Settings',
     visualExplain: 'Visual Explain',
     tez: 'Tez',
+    visualization: 'Visualization',
     notifications: 'Notifications',
     expand: 'Expand query panel',
     makeSettingGlobal: 'Make setting global',
@@ -113,7 +114,8 @@ TRANSLATIONS = {
       visualExplain: 'Visual Explain',
       tez: 'TEZ',
       status: 'Status: ',
-      messages: 'Messages'
+      messages: 'Messages',
+      visualization: 'Visualization'
     },
     download: 'Save results...',
     tableSample: '{{tableName}} sample'

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/visualization-tabs-widget.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/visualization-tabs-widget.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/visualization-tabs-widget.hbs
new file mode 100644
index 0000000..f46b709
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/components/visualization-tabs-widget.hbs
@@ -0,0 +1,27 @@
+{{!
+* 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.
+}}
+
+<ul class="nav nav-tabs">
+  {{#each tab in tabs}}
+      <li {{bind-attr class="tab.active:active"}} {{action 'selectTab' tab}}>
+        <a>{{tab.name}}</a>
+      </li>
+  {{/each}}
+</ul>
+
+<iframe {{bind-attr src=selectedTab.url}} id="visualization_frame" style="width:100%;height:1000px;border:0px;" allowfullscreen="true"></iframe>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visualization-ui.hbs
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visualization-ui.hbs b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visualization-ui.hbs
new file mode 100644
index 0000000..79c0f63
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/templates/visualization-ui.hbs
@@ -0,0 +1,32 @@
+{{!
+* 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 id="visualization" class="index-overlay">
+  {{#panel-widget headingTranslation="titles.query.visualization"}}
+    {{#if error}}
+      <div class="alert alert-danger" role="alert"><strong>{{error}}</strong></div>
+    {{else}}
+      {{#if polestarUrl}}
+        {{#visualization-tabs-widget tabs=visualizationTabs}}
+        {{/visualization-tabs-widget}}
+      {{else}}
+          <div class="alert alert-danger" role="alert"><strong>An unknown error occurred! Please try again later.</strong></div>
+      {{/if}}
+    {{/if}}
+  {{/panel-widget}}
+</div>

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
index e4e445a..c5d5cf0 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/utils/constants.js
@@ -38,7 +38,8 @@ export default Ember.Object.create({
       udfs: 'udfs',
       logs: 'logs',
       results: 'results',
-      explain: 'explain'
+      explain: 'explain',
+      visualization: 'visualization'
     },
 
     subroutes: {
@@ -219,5 +220,7 @@ export default Ember.Object.create({
 
   globalSettings: {
     comment: "--Global Settings--\n\n"
-  }
+  },
+
+  visualizationRowCount: 30000
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visualization-ui.js
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visualization-ui.js b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visualization-ui.js
new file mode 100644
index 0000000..b1c10df
--- /dev/null
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/app/views/visualization-ui.js
@@ -0,0 +1,37 @@
+/**
+ * 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.View.extend({
+  didInsertElement: function () {
+    var target = this.$('#visualization');
+    var panel = this.$('#visualization .panel-body').first();
+
+    panel.css('min-height', $('.main-content').height());
+    target.animate({ width: $('.main-content').width() }, 'fast');
+  },
+
+  willDestroyElement: function () {
+    var target = this.$('#visualization');
+    var panel = this.$('#visualization .panel-body');
+
+    panel.css('min-height', 0);
+    target.css('width', 0);
+  }
+});

http://git-wip-us.apache.org/repos/asf/ambari/blob/e54a453c/contrib/views/hive/src/main/resources/ui/hive-web/bower.json
----------------------------------------------------------------------
diff --git a/contrib/views/hive/src/main/resources/ui/hive-web/bower.json b/contrib/views/hive/src/main/resources/ui/hive-web/bower.json
index 37ea901..0b26eba 100644
--- a/contrib/views/hive/src/main/resources/ui/hive-web/bower.json
+++ b/contrib/views/hive/src/main/resources/ui/hive-web/bower.json
@@ -17,7 +17,9 @@
     "blanket": "~1.1.5",
     "jquery-ui": "~1.11.2",
     "selectize": "~0.12.0",
-    "pretender": "0.1.0"
+    "pretender": "0.1.0",
+    "polestar": "https://github.com/vivekratnavel/polestar.git",
+    "voyager": "https://github.com/vivekratnavel/voyager.git"
   },
   "resolutions": {
     "ember": "1.10.0"