瀏覽代碼

HUE-4833 [editor] Use the new SQL context-popover in assist and metastore

Johan Ahlen 9 年之前
父節點
當前提交
2bbf758b10

+ 4 - 3
apps/beeswax/src/beeswax/templates/create_database.mako

@@ -19,12 +19,12 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 %>
 
+<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
-<%namespace name="assist" file="/assist.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
 <%namespace name="require" file="/require.mako" />
-
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_("Create database"), 'metastore', user) | n,unicode }
 ${layout.metastore_menubar()}
@@ -33,6 +33,7 @@ ${ require.config() }
 
 ${ tableStats.tableStats() }
 ${ assist.assistPanel() }
+${ sqlContextPopover.sqlContextPopover() }
 
 <script src="${ static('desktop/ext/js/d3.v3.js') }" type="text/javascript" charset="utf-8"></script>
 

+ 4 - 3
apps/beeswax/src/beeswax/templates/create_table_manually.mako

@@ -19,12 +19,12 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 %>
 
+<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
-<%namespace name="assist" file="/assist.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
 <%namespace name="require" file="/require.mako" />
-
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_("Create table manually"), 'metastore', user) | n,unicode }
 ${ layout.metastore_menubar() }
@@ -33,6 +33,7 @@ ${ require.config() }
 
 ${ tableStats.tableStats() }
 ${ assist.assistPanel() }
+${ sqlContextPopover.sqlContextPopover() }
 
 <script src="${ static('desktop/ext/js/d3.v3.js') }" type="text/javascript" charset="utf-8"></script>
 

+ 4 - 3
apps/beeswax/src/beeswax/templates/execute.mako

@@ -22,11 +22,12 @@
   from notebook.conf import ENABLE_QUERY_BUILDER
 %>
 
+<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
-<%namespace name="layout" file="layout.mako" />
 <%namespace name="dashboard" file="common_dashboard.mako" />
+<%namespace name="layout" file="layout.mako" />
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
 <%namespace name="tableStats" file="/table_stats.mako" />
-<%namespace name="assist" file="/assist.mako" />
 
 ${ commonheader(_('Query'), app_name, user) | n,unicode }
 ${ layout.menubar(section='query') }
@@ -877,9 +878,9 @@ ${ commonshare() | n,unicode }
 <link rel="stylesheet" href="${ static('desktop/ext/select2/select2.css') }">
 <script src="${ static('desktop/ext/select2/select2.min.js') }" type="text/javascript" charset="utf-8"></script>
 
-
 ${ assist.assistPanel() }
 ${ tableStats.tableStats() }
+${ sqlContextPopover.sqlContextPopover() }
 
 <style type="text/css">
   h1 {

+ 5 - 5
apps/beeswax/src/beeswax/templates/import_wizard_choose_delimiter.mako

@@ -19,13 +19,13 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 %>
 
+<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
-<%namespace name="util" file="util.mako" />
 <%namespace name="layout" file="layout.mako" />
-<%namespace name="assist" file="/assist.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
 <%namespace name="require" file="/require.mako" />
-
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
+<%namespace name="util" file="util.mako" />
 
 ${ commonheader(_('Create table from file'), 'metastore', user) | n,unicode }
 ${ layout.metastore_menubar() }
@@ -34,7 +34,7 @@ ${ require.config() }
 
 ${ tableStats.tableStats() }
 ${ assist.assistPanel() }
-
+${ sqlContextPopover.sqlContextPopover() }
 
 <script src="${ static('desktop/ext/js/d3.v3.js') }" type="text/javascript" charset="utf-8"></script>
 

+ 4 - 4
apps/beeswax/src/beeswax/templates/import_wizard_choose_file.mako

@@ -19,12 +19,12 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 %>
 
+<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
 <%namespace name="layout" file="layout.mako" />
-<%namespace name="assist" file="/assist.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
 <%namespace name="require" file="/require.mako" />
-
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_('Create table from file'), 'metastore', user) | n,unicode }
 ${ layout.metastore_menubar() }
@@ -33,7 +33,7 @@ ${ require.config() }
 
 ${ tableStats.tableStats() }
 ${ assist.assistPanel() }
-
+${ sqlContextPopover.sqlContextPopover() }
 
 <script src="${ static('desktop/ext/js/d3.v3.js') }" type="text/javascript" charset="utf-8"></script>
 

+ 4 - 3
apps/beeswax/src/beeswax/templates/import_wizard_define_columns.mako

@@ -19,12 +19,13 @@ from desktop.views import commonheader, commonfooter
 from django.utils.translation import ugettext as _
 %>
 
+<%namespace name="assist" file="/assist.mako" />
 <%namespace name="comps" file="beeswax_components.mako" />
-<%namespace name="util" file="util.mako" />
 <%namespace name="layout" file="layout.mako" />
-<%namespace name="assist" file="/assist.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
 <%namespace name="require" file="/require.mako" />
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
+<%namespace name="util" file="util.mako" />
 
 
 ${ commonheader(_('Create table from file'), 'metastore', user) | n,unicode }

+ 42 - 0
apps/metastore/src/metastore/static/metastore/js/metastore.ko.js

@@ -605,6 +605,27 @@
     self.fetchDetails();
   };
 
+  MetastoreTable.prototype.showContextPopover = function (entry, event) {
+    var $source = $(event.target);
+    var offset = $source.offset();
+    huePubSub.publish('sql.context.popover.show', {
+      data: {
+        type: 'table',
+        identifierChain: [{ name: entry.name }]
+      },
+      orientation: 'right',
+      sourceType: 'hive',
+      defaultDatabase: entry.database.name,
+      source: {
+        element: event.target,
+        left: offset.left,
+        top: offset.top - 2,
+        right: offset.left + $source.width() + 1,
+        bottom: offset.top + $source.height() - 2
+      }
+    });
+  };
+
   /**
    * @param {Object} options
    * @param {MetastoreTable} options.table
@@ -639,6 +660,27 @@
     })
   }
 
+  MetastoreColumn.prototype.showContextPopover = function (entry, event) {
+    var $source = $(event.target);
+    var offset = $source.offset();
+    huePubSub.publish('sql.context.popover.show', {
+      data: {
+        type: 'column',
+        identifierChain: [{ name: entry.table.name }, { name: entry.name() }]
+      },
+      orientation: 'right',
+      sourceType: 'hive',
+      defaultDatabase: entry.table.database.name,
+      source: {
+        element: event.target,
+        left: offset.left,
+        top: offset.top - 2,
+        right: offset.left + $source.width() + 1,
+        bottom: offset.top + $source.height() - 2
+      }
+    });
+  };
+
   /**
    * @param {Object} options
    * @param {Object} options.i18n

+ 4 - 4
apps/metastore/src/metastore/templates/describe_partitions.mako

@@ -19,11 +19,11 @@
   from django.utils.translation import ugettext as _
 %>
 
-<%namespace name="components" file="components.mako" />
 <%namespace name="assist" file="/assist.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
+<%namespace name="components" file="components.mako" />
 <%namespace name="require" file="/require.mako" />
-
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_('Table Partitions: %(tableName)s') % dict(tableName=table.name), app_name, user) | n,unicode }
 ${ components.menubar() }
@@ -32,7 +32,7 @@ ${ require.config() }
 
 ${ tableStats.tableStats() }
 ${ assist.assistPanel() }
-
+${ sqlContextPopover.sqlContextPopover() }
 
 <script src="${ static('desktop/ext/js/d3.v3.js') }" type="text/javascript" charset="utf-8"></script>
 

+ 6 - 30
apps/metastore/src/metastore/templates/metastore.mako

@@ -25,10 +25,11 @@ from desktop.views import commonheader, commonfooter, _ko
 %>
 
 <%namespace name="actionbar" file="actionbar.mako" />
-<%namespace name="components" file="components.mako" />
 <%namespace name="assist" file="/assist.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
+<%namespace name="components" file="components.mako" />
 <%namespace name="require" file="/require.mako" />
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_("Metastore"), app_name, user) | n,unicode }
 ${ components.menubar() }
@@ -37,6 +38,7 @@ ${ require.config() }
 
 ${ tableStats.tableStats() }
 ${ assist.assistPanel() }
+${ sqlContextPopover.sqlContextPopover() }
 
 <script src="${ static('desktop/ext/js/bootstrap-editable.min.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/ext/js/d3.v3.js') }" type="text/javascript" charset="utf-8"></script>
@@ -101,9 +103,7 @@ ${ assist.assistPanel() }
       <thead>
       <tr>
         <th width="2%">&nbsp;</th>
-        ## no stats for partition key type
         <th width="2%" class="no-sort">&nbsp;</th>
-  ##       <th width="1%">&nbsp;</th>
         <th width="17%">${_('Name')}</th>
         <th width="15%">${_('Type')}</th>
         <!-- ko if: $root.optimizerEnabled  -->
@@ -114,23 +114,8 @@ ${ assist.assistPanel() }
       </thead>
       <tbody data-bind="hueach: {data: $data, itemHeight: 29, scrollable: '.right-panel', scrollableOffset: 200, disableHueEachRowCount: 5, scrollUp: true}">
         <tr>
-          ## start at 1
           <td data-bind="text: $index() + $indexOffset() + 1"></td>
-          ## no stats for partition key type
-          <td>
-           <span class="blue" data-bind="component: { name: 'table-stats', params: {
-              alwaysActive: true,
-              statsVisible: true,
-              sourceType: 'hive',
-              databaseName: table.database.name,
-              tableName: table.name,
-              columnName: name,
-              fieldType: type,
-              apiHelper: table.apiHelper,
-              showViewMore: false
-            } }"></span>
-          </td>
-  ##         <td class="pointer" data-bind="click: function() { favourite(!favourite()) }"><i style="color: #338bb8" class="fa" data-bind="css: {'fa-star': favourite, 'fa-star-o': !favourite() }"></i></td>
+          <td><a class="blue" href="javascript:void(0)" data-bind="click: showContextPopover"><i class="fa fa-bar-chart" title="${_('Show details')}"></i></a></td>
           <td title="${ _("Scroll to the column") }">
             <!-- ko if: $root.database().table().samples.loading() -->
             <span data-bind="text: name"></span>
@@ -473,16 +458,7 @@ ${ assist.assistPanel() }
               <td width="1%" style="text-align: center">
                 <div class="hueCheckbox fa" data-bind="multiCheck: '#tablesTable', value: $data, hueChecked: $parent.selectedTables"></div>
               </td>
-              <td width="1%"><span class="blue" data-bind="component: { name: 'table-stats', params: {
-                  alwaysActive: true,
-                  statsVisible: true,
-                  sourceType: 'hive',
-                  databaseName: database.name,
-                  tableName: name,
-                  fieldType: type,
-                  apiHelper: apiHelper,
-                  showViewMore: false
-                } }"></span></td>
+              <td width="1%"><a class="blue" href="javascript:void(0)" data-bind="click: showContextPopover"><i class="fa fa-bar-chart" title="${_('Show details')}"></i></a></td>
               <td>
                 <a class="tableLink" href="javascript:void(0);" data-bind="text: name, click: function() { $parent.setTable($data, function(){ huePubSub.publish('metastore.url.change'); }) }"></a>
               </td>

+ 25 - 0
desktop/core/src/desktop/static/desktop/js/assist/assistDbEntry.js

@@ -138,6 +138,31 @@
     });
   }
 
+  AssistDbEntry.prototype.showContextPopover = function (entry, event) {
+    var $source = $(event.target);
+    var offset = $source.offset();
+    entry.statsVisible(true);
+    huePubSub.publish('sql.context.popover.show', {
+      data: {
+        type: entry.definition.isColumn ? 'column' : 'table',
+        identifierChain: entry.definition.isColumn ? [{ name: entry.tableName }, { name: entry.columnName }] : [{ name: entry.tableName }]
+      },
+      orientation: 'right',
+      sourceType: entry.sourceType,
+      defaultDatabase: entry.databaseName,
+      source: {
+        element: event.target,
+        left: offset.left,
+        top: offset.top - 2,
+        right: offset.left + $source.width() + 1,
+        bottom: offset.top + $source.height() - 2
+      }
+    });
+    huePubSub.subscribeOnce('sql.context.popover.hidden', function () {
+      entry.statsVisible(false);
+    });
+  };
+
   AssistDbEntry.prototype.toggleSearch = function () {
     var self = this;
     self.isSearchVisible(!self.isSearchVisible());

+ 2 - 1
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -3001,7 +3001,8 @@
               var endCoordinates = editor.renderer.textToScreenCoordinates(range.end.row, range.end.column);
               huePubSub.publish('sql.context.popover.show', {
                 data: token.parseLocation,
-                snippet: snippet,
+                sourceType: snippet.type(),
+                defaultDatabase: snippet.database(),
                 source: {
                   left: startCoordinates.pageX - 3,
                   top: startCoordinates.pageY,

+ 2 - 11
desktop/core/src/desktop/templates/assist.mako

@@ -419,16 +419,7 @@ from metadata.conf import has_navigator
 
   <script type="text/html" id="assist-entry-actions">
     <div class="assist-actions" data-bind="css: { 'table-actions' : definition.isTable || definition.isView, 'column-actions': definition.isColumn, 'database-actions' : definition.isDatabase } " style="opacity: 0">
-      <span data-bind="visible: navigationSettings.showStats, component: { name: 'table-stats', params: {
-          statsVisible: statsVisible,
-          sourceType: sourceType,
-          snippet: assistDbSource.snippet,
-          databaseName: databaseName,
-          tableName: tableName,
-          columnName: columnName,
-          fieldType: definition.type,
-          apiHelper: assistDbSource.apiHelper
-        } }"></span>
+      <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.showStats, click: showContextPopover, css: { 'blue': statsVisible }"><i class="fa fa-bar-chart" title="${_('Show details')}"></i></a>
       <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.openItem || (navigationSettings.openDatabase && definition.isDatabase), click: openItem"><i class="fa fa-long-arrow-right" title="${_('Open')}"></i></a>
     </div>
   </script>
@@ -436,7 +427,7 @@ from metadata.conf import has_navigator
   <script type="text/html" id="assist-table-entry">
     <li class="assist-table" data-bind="visibleOnHover: { override: statsVisible, selector: '.table-actions' }">
       <div class="assist-actions table-actions" style="opacity: 0">
-        <span data-bind="visible: navigationSettings.showStats, component: { name: 'table-stats', params: { statsVisible: statsVisible, sourceType: sourceType, snippet: assistDbSource.snippet, databaseName: databaseName, tableName: tableName, columnName: columnName, fieldType: definition.type, apiHelper: assistDbSource.apiHelper }}"></span>
+        <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.showStats, click: showContextPopover, css: { 'blue': statsVisible }"><i class="fa fa-bar-chart" title="${_('Show details')}"></i></a>
         <a class="inactive-action" href="javascript:void(0)" data-bind="visible: navigationSettings.openItem, click: openItem"><i class="fa fa-long-arrow-right" title="${_('Open')}"></i></a>
       </div>
       <a class="assist-entry assist-table-link" href="javascript:void(0)" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.title }, draggableText: { text: editorText,  meta: {'type': 'sql', 'table': tableName, 'database': databaseName} }"><i class="fa fa-fw fa-table muted valign-middle"></i><span data-bind="text: definition.displayName, css: { 'highlight': highlight }"></span></a>

+ 3 - 1
desktop/core/src/desktop/templates/home2.mako

@@ -20,8 +20,9 @@
 
 <%namespace name="assist" file="/assist.mako" />
 <%namespace name="fileBrowser" file="/file_browser.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
 <%namespace name="require" file="/require.mako" />
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_('Welcome Home'), "home", user) | n,unicode }
 
@@ -29,6 +30,7 @@ ${ require.config() }
 
 ${ tableStats.tableStats() }
 ${ assist.assistPanel() }
+${ sqlContextPopover.sqlContextPopover() }
 ${ fileBrowser.fileBrowser() }
 
 <style type="text/css">

+ 56 - 37
desktop/core/src/desktop/templates/sql_context_popover.mako

@@ -32,7 +32,7 @@ from metadata.conf import has_navigator
       left: 0;
       z-index: 1060;
       width: 450px;
-      height: 425px;
+      height: 400px;
       padding: 1px;
       background-color: #fff;
       -webkit-background-clip: padding-box;
@@ -444,10 +444,19 @@ from metadata.conf import has_navigator
 
       var preventHide = false;
 
+      var intervals = [];
+      var pubSubs = [];
+
       var hidePopover = function () {
         if (! preventHide) {
           $('#sqlContextPopover').remove();
           $(document).off('click', hideOnClickOutside);
+          while (intervals.length > 0) {
+            window.clearInterval(intervals.pop());
+          }
+          while (pubSubs.length > 0) {
+            pubSubs.pop().remove();
+          }
           huePubSub.publish('sql.context.popover.dispose');
           huePubSub.publish('sql.context.popover.hidden');
         }
@@ -459,10 +468,11 @@ from metadata.conf import has_navigator
         }
       };
 
-      function TableAndColumnTabContents(identifierChain, snippet, apiFunction) {
+      function TableAndColumnTabContents(identifierChain, sourceType, defaultDatabase, apiFunction) {
         var self = this;
         self.identifierChain = identifierChain;
-        self.snippet = snippet;
+        self.sourceType = sourceType;
+        self.defaultDatabase = defaultDatabase;
         self.apiHelper = ApiHelper.getInstance();
         self.apiFunction = apiFunction;
 
@@ -490,9 +500,9 @@ from metadata.conf import has_navigator
         self.hasErrors(false);
 
         self.apiFunction.bind(self.apiHelper)({
-          sourceType: self.snippet.type(),
+          sourceType: self.sourceType,
           identifierChain: self.identifierChain,
-          defaultDatabase: self.snippet.database(),
+          defaultDatabase: self.defaultDatabase,
           silenceErrors: true,
           successCallback: function (data) {
             if (typeof data.extended_columns !== 'undefined') {
@@ -516,16 +526,16 @@ from metadata.conf import has_navigator
         });
       };
 
-      function TableAndColumnContextTabs(data, snippet, isColumn) {
+      function TableAndColumnContextTabs(data, sourceType, defaultDatabase, isColumn) {
         var self = this;
         self.tabs = ko.observableArray();
 
         var apiHelper = ApiHelper.getInstance();
 
-        self.details = new TableAndColumnTabContents(data.identifierChain, snippet, apiHelper.fetchAutocomplete);
-        self.sample = new TableAndColumnTabContents(data.identifierChain, snippet, apiHelper.fetchSamples);
-        self.analysis = new TableAndColumnTabContents(data.identifierChain, snippet, apiHelper.fetchAnalysis);
-        self.partitions = new TableAndColumnTabContents(data.identifierChain, snippet, apiHelper.fetchPartitions);
+        self.details = new TableAndColumnTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchAutocomplete);
+        self.sample = new TableAndColumnTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchSamples);
+        self.analysis = new TableAndColumnTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchAnalysis);
+        self.partitions = new TableAndColumnTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchPartitions);
 
         self.activeTab = ko.observable('details');
 
@@ -579,7 +589,7 @@ from metadata.conf import has_navigator
           }
         });
 
-        var samplesInterval = window.setInterval(function () {
+        intervals.push(window.setInterval(function () {
           if (self.activeTab() !== 'sample') {
             return;
           }
@@ -593,7 +603,7 @@ from metadata.conf import has_navigator
             $t.data('plugin_jHueTableExtender').drawFirstColumn();
           }
           $t.parents('.dataTables_wrapper').getNiceScroll().resize();
-        }, 300);
+        }, 300));
 
         var performScrollToColumn = function (colName) {
           self.activeTab('sample');
@@ -618,7 +628,7 @@ from metadata.conf import has_navigator
           }, 0);
         };
 
-        var scrollToSubscription = huePubSub.subscribe('sql.context.popover.scroll.to.column', function (colName) {
+        pubSubs.push(huePubSub.subscribe('sql.context.popover.scroll.to.column', function (colName) {
           if (typeof self.sample.fetchedData() === 'undefined') {
             self.sample.fetch(function (data) {
               self.initializeSamplesTable(data);
@@ -629,27 +639,19 @@ from metadata.conf import has_navigator
           } else {
             performScrollToColumn(colName);
           }
-        });
+        }));
 
-        var showInAssistSubscription = huePubSub.subscribe('sql.context.popover.show.in.assist', function () {
+        pubSubs.push(huePubSub.subscribe('sql.context.popover.show.in.assist', function () {
           huePubSub.publish('assist.db.highlight', {
-            sourceType: snippet.type(),
-            path: apiHelper.identifierChainToPath(data.identifierChain, snippet.database())
+            sourceType: sourceType,
+            path: apiHelper.identifierChainToPath(data.identifierChain, defaultDatabase)
           });
           huePubSub.publish('sql.context.popover.hide')
-        });
-
-        var openInMetastoreSubscription = huePubSub.subscribe('sql.context.popover.open.in.metastore', function () {
-          window.open('/metastore/table/' + apiHelper.identifierChainToPath(data.identifierChain, snippet.database()).join('/'), '_blank');
-        });
+        }));
 
-        var disposeSubscription = huePubSub.subscribe('sql.context.popover.dispose', function () {
-          window.clearInterval(samplesInterval);
-          disposeSubscription.remove();
-          scrollToSubscription.remove();
-          openInMetastoreSubscription.remove();
-          showInAssistSubscription.remove();
-        });
+        pubSubs.push(huePubSub.subscribe('sql.context.popover.open.in.metastore', function () {
+          window.open('/metastore/table/' + apiHelper.identifierChainToPath(data.identifierChain, defaultDatabase).join('/'), '_blank');
+        }));
       }
 
       TableAndColumnContextTabs.prototype.initializeSamplesTable = function (data) {
@@ -719,10 +721,10 @@ from metadata.conf import has_navigator
         }, 0);
       };
 
-      function FunctionContextTabs(data, snippet) {
+      function FunctionContextTabs(data, sourceType) {
         var self = this;
         self.func = ko.observable({
-          details: sqlFunctions.findFunction(snippet.type(), data.function),
+          details: sqlFunctions.findFunction(sourceType, data.function),
           loading: ko.observable(false),
           hasErrors: ko.observable(false)
         });
@@ -811,21 +813,38 @@ from metadata.conf import has_navigator
 
       function SqlContextPopoverViewModel(params) {
         var self = this;
-        self.left = ko.observable();
-        self.top = ko.observable();
+        self.left = ko.observable(0);
+        self.top = ko.observable(0);
         self.data = params.data;
-        self.snippet = params.snippet;
+        self.sourceType = params.sourceType;
+        self.defaultDatabase = params.defaultDatabase;
         self.close = hidePopover;
         var orientation = params.orientation || 'bottom';
         self.contents = null;
         self.resizeHelper = new ResizeHelper(orientation);
 
+        if (typeof params.source.element !== 'undefined') {
+          // Track the source element and close the popover if moved
+          var $source = $(params.source.element);
+          var originalSourceOffset = $source.offset();
+          var currentSourceOffset;
+          intervals.push(window.setInterval(function () {
+            currentSourceOffset = $source.offset();
+            if (currentSourceOffset.left !== originalSourceOffset.left || currentSourceOffset.top !== originalSourceOffset.top) {
+              hidePopover();
+            }
+          }, 200));
+
+        }
+
         switch (orientation) {
           case 'top':
             self.left(params.source.left + Math.round((params.source.right - params.source.left) / 2) - 225);
             self.top(params.source.top - 300);
             break;
           case 'right':
+            self.left(params.source.right);
+            self.top(params.source.top + Math.round((params.source.bottom - params.source.top) / 2) - 200);
             break;
           case 'bottom':
             self.left(params.source.left + Math.round((params.source.right - params.source.left) / 2) - 225);
@@ -839,15 +858,15 @@ from metadata.conf import has_navigator
         self.isFunction = params.data.type === 'function';
 
         if (self.isTable) {
-          self.contents = new TableAndColumnContextTabs(self.data, self.snippet, false);
+          self.contents = new TableAndColumnContextTabs(self.data, self.sourceType, self.defaultDatabase, false);
           self.title = self.data.identifierChain[self.data.identifierChain.length - 1].name;
           self.iconClass = 'fa-table'
         } else if (self.isColumn) {
-          self.contents = new TableAndColumnContextTabs(self.data, self.snippet, true);
+          self.contents = new TableAndColumnContextTabs(self.data, self.sourceType, self.defaultDatabase, true);
           self.title = self.data.identifierChain[self.data.identifierChain.length - 1].name;
           self.iconClass = 'fa-columns'
         } else if (self.isFunction) {
-          self.contents = new FunctionContextTabs(self.data, self.snippet);
+          self.contents = new FunctionContextTabs(self.data, self.sourceType);
           self.title = self.data.function;
           self.iconClass = 'fa-superscript'
         } else {

+ 3 - 1
desktop/libs/indexer/src/indexer/templates/indexer.mako

@@ -22,8 +22,9 @@
 
 <%namespace name="actionbar" file="actionbar.mako" />
 <%namespace name="assist" file="/assist.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
 <%namespace name="require" file="/require.mako" />
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_("Solr Indexes"), "search", user, "60px") | n,unicode }
 
@@ -31,6 +32,7 @@ ${ require.config() }
 
 ${ tableStats.tableStats() }
 ${ assist.assistPanel() }
+${ sqlContextPopover.sqlContextPopover() }
 
 <link rel="stylesheet" href="${ static('notebook/css/notebook.css') }">
 <link rel="stylesheet" href="${ static('desktop/css/wizard.css') }">

+ 3 - 3
desktop/libs/notebook/src/notebook/templates/editor.mako

@@ -19,12 +19,12 @@
   from django.utils.translation import ugettext as _
 %>
 
-<%namespace name="configKoComponents" file="/config_ko_components.mako" />
-<%namespace name="tableStats" file="/table_stats.mako" />
-<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
 <%namespace name="assist" file="/assist.mako" />
+<%namespace name="configKoComponents" file="/config_ko_components.mako" />
 <%namespace name="editorComponents" file="editor_components.mako" />
 <%namespace name="notebookKoComponents" file="notebook_ko_components.mako" />
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_('Editor'), editor_type, user, "68px") | n,unicode }
 

+ 2 - 2
desktop/libs/notebook/src/notebook/templates/notebook.mako

@@ -19,12 +19,12 @@
   from django.utils.translation import ugettext as _
 %>
 
-<%namespace name="tableStats" file="/table_stats.mako" />
-<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
 <%namespace name="assist" file="/assist.mako" />
 <%namespace name="configKoComponents" file="/config_ko_components.mako" />
 <%namespace name="editorComponents" file="editor_components.mako" />
 <%namespace name="notebookKoComponents" file="notebook_ko_components.mako" />
+<%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
+<%namespace name="tableStats" file="/table_stats.mako" />
 
 ${ commonheader(_('Notebook'), app_name, user, "68px") | n,unicode }