浏览代码

HUE-7049 [frontend] Generify the context popover and get rid of unused code

Johan Ahlen 8 年之前
父节点
当前提交
b7d1118d92

+ 0 - 3
desktop/conf.dist/hue.ini

@@ -176,9 +176,6 @@
   # e.g. Query result in Editors and Dashboards, file in File Browser...
   ## enable_download=true
 
-  # Choose whether to enable the new generic context popover or not.
-  ## use_new_context_popover=false
-
   # Choose whether to enable SQL syntax check or not
   ## enable_sql_syntax_check=true
 

+ 0 - 7
desktop/core/src/desktop/conf.py

@@ -1319,13 +1319,6 @@ ENABLE_SQL_SYNTAX_CHECK = Config(
   help=_('Choose whether to enable SQL syntax check or not.')
 )
 
-USE_NEW_CONTEXT_POPOVER = Config( # To remove when the new context popover is ready
-  key='use_new_context_popover',
-  default=False,
-  type=coerce_bool,
-  help=_('Choose whether to use the new context popover or not.')
-)
-
 USE_NEW_AUTOCOMPLETER = Config( # This now refers to the new autocomplete dropdown
   key='use_new_autocompleter',
   default=True,

文件差异内容过多而无法显示
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue.css


文件差异内容过多而无法显示
+ 0 - 0
desktop/core/src/desktop/static/desktop/css/hue3-extra.css


+ 19 - 18
desktop/core/src/desktop/static/desktop/less/hue-assist.less

@@ -611,7 +611,7 @@
 
 // --- Context Popover ---
 
-.sql-context-popover-content {
+.context-popover-content {
   .display-flex();
   .flex(1 1 100%);
   .flex-direction(column);
@@ -619,14 +619,14 @@
   overflow: hidden;
 }
 
-.sql-context-tab-pane {
+.context-popover-tab-pane {
   position: absolute;
   top: 0;
   bottom: 0;
   width: 100%;
 }
 
-.sql-context-tabs {
+.context-popover-tabs {
   .flex(0 1 auto);
   border-bottom: 1px solid @cui-default-border-color;
   margin-left: -1px;
@@ -634,20 +634,20 @@
   padding-left: 15px;
 }
 
-.sql-context-tab-container {
+.context-popover-tab-container {
   position: relative;
   .flex(1 1 100%);
   border: none;
   overflow: auto;
 }
 
-.sql-context-tab {
+.context-popover-tab {
   padding-top: 0 !important;
   padding-bottom: 5px !important;
   margin-bottom: -1px !important
 }
 
-.sql-context-flex {
+.context-popover-flex {
   .display-flex();
   .flex-flow(column nowrap);
   position: absolute;
@@ -656,11 +656,11 @@
   width: 100%;
 }
 
-.sql-context-flex-header {
+.context-popover-flex-header {
   .flex(0 0 35px);
 }
 
-.sql-context-flex-fill {
+.context-popover-flex-fill {
   overflow: hidden;
   position: relative;
   margin: 0 10px;
@@ -670,37 +670,38 @@
     margin: 0 5px;
   }
 }
-.sql-context-table-details {
+
+.context-popover-table-details {
   .flex(1);
   padding: 10px 10px 0 10px;
 }
 
-.sql-context-header {
+.context-popover-header {
   font-size: 15px;
   margin: 10px;
 }
 
-.sql-context-section {
+.context-popover-section {
   margin-left: 15px;
 }
 
-.sql-context-flex-bottom-links {
+.context-popover-flex-bottom-links {
   .flex(0 0 35px);
   border-top: 1px solid @cui-default-border-color;
   z-index: 100;
   background-color: @cui-white;
 }
 
-.sql-context-link-row {
+.context-popover-link-row {
   float: right;
   margin: 8px 15px 0 10px;
 }
 
-.sql-context-link-row a {
+.context-popover-link-row a {
   margin-left: 10px;
 }
 
-.sql-context-inline-search {
+.context-popover-inline-search {
   border-radius: 8px !important;
   min-height: 18px !important;
   height: 18px !important;
@@ -708,7 +709,7 @@
   padding-right: 18px !important;
 }
 
-.sql-context-empty-columns {
+.context-popover-empty-columns {
   letter-spacing: 0.035em;
   margin-top: 50px;
   font-size: 14px;
@@ -716,7 +717,7 @@
   text-align: center;
 }
 
-.context-sample {
+.context-popover-sample {
   text-align: left;
   padding: 3px;
   overflow: hidden;
@@ -752,7 +753,7 @@
   }
 }
 
-.sql-context-flex-fill.context-sample-container {
+.context-popover-flex-fill.context-popover-sample-container {
   margin: 0;
 }
 

+ 3 - 4
desktop/core/src/desktop/static/desktop/less/hue.less

@@ -789,8 +789,7 @@ a:visited {
   background-color: @cui-gray-200;
 }
 
-#contextPopover .hue-popover,
-#sqlContextPopover .hue-popover {
+#contextPopover .hue-popover {
   position: fixed;
 }
 
@@ -1080,11 +1079,11 @@ a:visited {
     .display-flex();
     .flex(1);
 
-    .sql-context-tab {
+    .context-popover-tab {
       background-color: transparent !important;
     }
 
-    .sql-context-inline-search {
+    .context-popover-inline-search {
       width: 180px !important;
     }
   }

+ 0 - 5
desktop/core/src/desktop/templates/assist.mako

@@ -54,15 +54,10 @@ from notebook.conf import ENABLE_QUERY_BUILDER, ENABLE_QUERY_SCHEDULING, get_ord
       home_dir = '/'
   %>
 
-  <%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
   <%namespace name="contextPopover" file="/context_popover.mako" />
   <%namespace name="nav_components" file="/nav_components.mako" />
 
-  % if conf.USE_NEW_CONTEXT_POPOVER.get():
   ${ contextPopover.contextPopover() }
-  % else:
-  ${ sqlContextPopover.sqlContextPopover() }
-  %endif
   ${ nav_components.nav_tags(readOnly=not user.has_hue_permission(action="write", app="metadata")) }
 
   <script type="text/html" id="assist-no-database-entries">

文件差异内容过多而无法显示
+ 963 - 77
desktop/core/src/desktop/templates/context_popover.mako


+ 1 - 1
desktop/core/src/desktop/templates/ko_components.mako

@@ -641,7 +641,7 @@ from desktop.views import _ko
         <!-- ko with: selectedResult -->
           <!-- ko switch: type -->
             <!-- ko case: ['database', 'document', 'field', 'table', 'view']  -->
-              <!-- ko component: { name: 'sql-context-contents-global-search', params: { data: data, globalSearch: $parent } } --><!-- /ko -->
+              <!-- ko component: { name: 'context-popover-contents-global-search', params: { data: data, globalSearch: $parent } } --><!-- /ko -->
             <!-- /ko -->
             <!-- ko case: $default -->
               <pre data-bind="text: ko.mapping.toJSON($data)"></pre>

+ 0 - 1647
desktop/core/src/desktop/templates/sql_context_popover.mako

@@ -1,1647 +0,0 @@
-## Licensed to Cloudera, Inc. under one
-## or more contributor license agreements.  See the NOTICE file
-## distributed with this work for additional information
-## regarding copyright ownership.  Cloudera, Inc. 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.
-
-<%!
-from django.utils.translation import ugettext as _
-
-from dashboard.conf import HAS_SQL_ENABLED
-from desktop import conf
-from desktop.conf import USE_NEW_SIDE_PANELS
-from desktop.lib.i18n import smart_unicode
-from desktop.views import _ko
-
-from metadata.conf import has_navigator
-%>
-
-<%def name="sqlContextPopover()">
-  <script type="text/html" id="sql-context-footer">
-    <div class="sql-context-flex-bottom-links">
-      <div class="sql-context-link-row">
-        <a class="inactive-action pointer" data-bind="visible: showInAssistEnabled && (isTable || isColumn), click: function() { huePubSub.publish('context.popover.show.in.assist') }">
-          <i style="font-size: 11px;" title="${ _("Show in Assist...") }" class="fa fa-search"></i> ${ _("Assist") }
-        </a>
-        % if HAS_SQL_ENABLED.get():
-        <a class="inactive-action pointer" data-bind="visible: (typeof isTable !== 'undefined' && isTable) || (typeof isView !== 'undefined' && isView) || (typeof isDatabase !== 'undefined' && isDatabase), click: function() { huePubSub.publish('context.popover.open.in.dashboard') }">
-          <i style="font-size: 11px;" title="${ _("Open in Dashboard...") }" class="fa fa-external-link"></i> ${ _("Dashboard") }
-        </a>
-        % endif
-        <a class="inactive-action pointer" data-bind="visible: (typeof isTable !== 'undefined' && isTable) || (typeof isView !== 'undefined' && isView) || (typeof isDatabase !== 'undefined' && isDatabase), click: function() { huePubSub.publish('context.popover.open.in.metastore', isTable ? 'table' : 'db') }">
-          <i style="font-size: 11px;" title="${ _("Open in Table Browser...") }" class="fa fa-external-link"></i> ${ _("Table Browser") }
-        </a>
-        <a class="inactive-action pointer" data-bind="visible: typeof isHdfs !== 'undefined' && isHdfs, click: function() { huePubSub.publish('context.popover.replace.in.editor') }">
-          <i style="font-size: 11px;" title="${ _("Replace the editor content...") }" class="fa fa-pencil"></i> ${ _("Insert in the editor") }
-        </a>
-        <a class="inactive-action pointer" data-bind="visible: typeof isHdfs !== 'undefined' && isHdfs, click: function() { huePubSub.publish('context.popover.open.in.file.browser') }">
-          <i style="font-size: 11px;" title="${ _("Open in File Browser...") }" class="fa fa-external-link"></i> ${ _("File Browser") }
-        </a>
-        <!-- ko if: typeof isAsterisk !== 'undefined' && isAsterisk -->
-        <!-- ko with: contents.data -->
-        <!-- ko if: selectedColumns().length > 0 -->
-        <a class="inactive-action pointer" data-bind="click: expand">${ _("Expand to selected columns") }</a>
-        <!-- /ko -->
-        <!-- ko if: selectedColumns().length === 0 -->
-        <a class="inactive-action pointer" data-bind="click: expand">${ _("Expand to all columns") }</a>
-        <!-- /ko -->
-        <!-- /ko -->
-        <!-- /ko -->
-      </div>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-columns">
-    <div class="sql-context-flex-fill" data-bind="with: fetchedData">
-      <!-- ko component: { name: 'sql-columns-table', params: { columns: extended_columns } } --><!-- /ko -->
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-table-details">
-    <!-- ko with: fetchedData -->
-    <div class="sql-context-table-details">
-      <!-- ko if: details && details.properties -->
-      <div class="sql-context-header">${ _("Properties") }</div>
-      <div class="sql-context-section">
-        <span style="margin-right: 5px;" title="${ _('Owner') }">
-          <i class="fa fa-fw fa-user muted"></i> <span data-bind="text: details.properties.owner"></span>
-        </span>
-        <span style="margin-right: 5px;" title="${ _('Created') }">
-          <i class="fa fa-fw fa-clock-o muted"></i> <span data-bind="text: localeFormat(details.properties.create_time)"></span>
-        </span>
-        <span style="margin-right: 5px;" title="${ _('Format') }">
-          <i class="fa fa-fw fa-file-o muted"></i> <span data-bind="text: details.properties.format"></span>
-        </span>
-        <span style="margin-right: 5px; white-space: nowrap" title="${ _('Type') }">
-          <i class="fa fa-fw fa-archive muted"></i> <span data-bind="visible: details.properties.table_type === 'MANAGED_TABLE'" style="display:none;">${_('Managed')}</span><span data-bind="visible: !details.stats.table_type === 'EXTERNAL_TABLE'" style="display:none;">${_('External')}</span>
-        </span>
-      </div>
-      <!-- /ko -->
-      <!-- ko if: typeof comment !== 'undefined' && comment !== '' && comment !== null -->
-      <div class="sql-context-header">${ _("Comment") }</div>
-      <div class="sql-context-section" style="font-style: italic;" data-bind="text: comment"></div>
-      <!-- /ko -->
-      %if has_navigator(user):
-        <!-- ko if: $parent.sourceType === 'hive' || $parent.sourceType === 'impala' -->
-        <div class="sql-context-header">${ _("Tags") }</div>
-        <div class="sql-context-section" data-bind="component: { name: 'nav-tags', params: $parent } "></div>
-        <!-- /ko -->
-      %endif
-      <!-- ko if: typeof viewSql !== 'undefined' -->
-      <div class="sql-context-header">${ _("View SQL") }</div>
-      <!-- ko hueSpinner: { spin: loadingViewSql, center: true, size: 'large' } --><!-- /ko -->
-      <!-- ko ifnot: loadingViewSql -->
-      <div class="sql-context-section" class="pointer" title="${ _("Click to copy") }" data-bind="tooltip: { placement: 'bottom' }, clickToCopy: viewSql, click: function () { huePubSub.publish('context.popover.hide'); }, highlight: { value: viewSql, formatted: true, dialect: $parent.sourceType }"></div>
-      <!-- /ko -->
-      <!-- /ko -->
-    </div>
-    <!-- /ko -->
-  </script>
-
-  <script type="text/html" id="sql-context-column-details">
-    <div class="sql-context-flex-fill" data-bind="with: fetchedData, nicescroll">
-      <div>
-        <div style="margin: 0 0 5px 10px;"><a class="pointer" data-bind="text: name, attr: { title: name }, click: function() { huePubSub.publish('context.popover.scroll.to.column', name); }"></a> <!-- ko if: typeof type !== 'undefined' -->(<span data-bind="text: type.indexOf('<') !== -1 ? type.substring(0, type.indexOf('<')) : type, attr: { title: type }"></span>)<!-- /ko --></div>
-        <!-- ko if: typeof comment !== 'undefined' && comment !== '' && comment !== null -->
-        <div class="sql-context-header">${ _("Comment") }</div>
-        <div class="sql-context-section" data-bind="text: comment"></div>
-        <!-- /ko -->
-        %if has_navigator(user):
-          <!-- ko if: $parent.sourceType === 'hive' || $parent.sourceType === 'impala' -->
-          <div class="sql-context-header">${ _("Tags") }</div>
-          <div class="sql-context-section" data-bind="component: { name: 'nav-tags', params: $parent } "></div>
-          <!-- /ko -->
-        %endif
-      </div>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-complex-details">
-    <div class="sql-context-flex-fill" data-bind="with: fetchedData, nicescroll">
-      <div style="margin: 15px;">
-        <a class="pointer" data-bind="visible: typeof sample !== 'undefined', text: name || $parents[2].title, attr: { title: name || $parents[2].title }, click: function() { huePubSub.publish('context.popover.scroll.to.column', name || $parents[2].title); }"></a>
-        <span data-bind="visible: typeof sample === 'undefined', text: name || $parents[2].title, attr: { title: name || $parents[2].title }"></span> <!-- ko if: typeof type !== 'undefined' -->(<span data-bind="text: type.indexOf('<') !== -1 ? type.substring(0, type.indexOf('<')) : type, attr: { title: type }"></span>)<!-- /ko -->
-      </div>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-table-and-column-unknown">
-    <div class="sql-context-flex-fill">
-      <div style="margin: 15px;">
-        <div class="alert" data-bind="text: message"></div>
-      </div>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-table-and-column-sample">
-    <div class="sql-context-flex-fill context-sample-container" data-bind="with: fetchedData">
-      <div class="context-sample sample-scroll">
-        <!-- ko if: rows.length == 0 -->
-        <div class="alert">${ _('The selected table has no data.') }</div>
-        <!-- /ko -->
-        <!-- ko if: rows.length > 0 -->
-        <table id="samples-table" class="samples-table table table-condensed">
-          <thead>
-          <tr>
-            <th style="width: 10px">&nbsp;</th>
-            <!-- ko foreach: headers -->
-            <th data-bind="text: $data"></th>
-            <!-- /ko -->
-          </tr>
-          </thead>
-          <tbody>
-          </tbody>
-        </table>
-        <!-- /ko -->
-      </div>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-table-analysis">
-    <div class="sql-context-flex-fill" data-bind="with: fetchedData, niceScroll">
-      <!-- ko if: stats.length > 0 -->
-        <table class="table table-condensed">
-          <tbody data-bind="foreach: stats">
-            <tr>
-              <td><strong data-bind="text: data_type"></strong></td>
-              <td data-bind="text: $parents[1].formatAnalysisValue(data_type, comment)"></td>
-            </tr>
-          </tbody>
-        </table>
-      <!-- /ko -->
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-column-analysis">
-    <div class="sql-context-flex-fill" data-bind="with: fetchedData, niceScroll">
-      <table class="table table-condensed">
-        <tbody data-bind="foreach: stats">
-          <tr>
-            <td><strong data-bind="text: Object.keys($data)[0]"></strong></td>
-            <td data-bind="text: $data[Object.keys($data)[0]]"></td>
-          </tr>
-        </tbody>
-      </table>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-database-details">
-    <div class="sql-context-flex-fill">
-      <div class="sql-context-flex">
-        <div data-bind="if: $parent.comment">
-          <div class="sql-context-header">${ _("Comment") }</div>
-          <div class="sql-context-section" style="font-style: italic;" data-bind="text: $parent.comment"></div>
-        </div>
-        <div class="sql-context-header">${_('Tags')}</div>
-        <div class="sql-context-flex-fill sql-columns-table" style="position:relative; height: 100%; overflow-y: auto;">
-          <div data-bind="component: { name: 'nav-tags', params: $data } "></div>
-        </div>
-      </div>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-hdfs-details">
-    <div class="sql-context-flex-fill" data-bind="with: details, niceScroll">
-      <div style="padding: 8px">
-        <div style="margin: 10px 10px 18px 10px;">
-          <div data-bind="hdfsTree: { isS3: $data.path.indexOf('s3a://') === 0, path: $data.path, selectedPath: $parent.selectedPath }"></div>
-        </div>
-      </div>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-asterisk-details">
-    <div class="sql-context-flex-fill">
-      <!-- ko component: { name: 'sql-columns-table', params: { columns: columns, scrollToColumns: false } } --><!-- /ko -->
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-function-details">
-    <!-- ko if: typeof details === 'undefined' -->
-    <div class="sql-context-flex-fill">
-      <div class="alert">${_('Could not find details for the function')} <span data-bind="text: $parents[2].title"></span>()</div>
-    </div>
-    <!-- /ko -->
-    <!-- ko if: typeof details !== 'undefined' -->
-    <div class="sql-context-flex-fill" data-bind="with: details, niceScroll">
-      <div style="padding: 8px">
-        <p style="margin: 10px 10px 18px 10px;"><span style="white-space: pre;" class="monospace" data-bind="text: signature"></span></p>
-        <p><span data-bind="text: description"></span></p>
-      </div>
-    </div>
-    <!-- /ko -->
-  </script>
-
-  <script type="text/html" id="sql-context-table-partitions">
-    <div class="sql-context-flex-fill" data-bind="with: fetchedData, niceScroll">
-      <div class="sql-context-header">${_('Columns')}</div>
-      <div>
-        <table class="table table-condensed table-nowrap">
-          <thead>
-          <tr>
-            <th style="width: 1%">&nbsp;</th>
-            <th>${_('Name')}</th>
-          </tr>
-          </thead>
-          <tbody data-bind="foreach: partition_keys_json">
-          <tr>
-            <td data-bind="text: $index() + 1"></td>
-            <td><a href="#" data-bind="text: $data, click: function() { huePubSub.publish('context.popover.scroll.to.column', $data); }"></a></td>
-          </tr>
-          </tbody>
-        </table>
-      </div>
-      <div class="sql-context-header">${_('Partitions')}</div>
-      <table class="table table-condensed table-nowrap">
-        <thead>
-          <tr>
-            <th style="width: 1%">&nbsp;</th>
-            <th>${_('Values')}</th>
-            <th>${_('Spec')}</th>
-            <th>${_('Browse')}</th>
-          </tr>
-        </thead>
-        <tbody data-bind="foreach: partition_values_json">
-          <tr>
-            <td data-bind="text: $index() + 1"></td>
-            <td><a href="#" data-bind="click: function () { window.open(readUrl, '_blank'); return false; }, text: '[\'' + columns.join('\',\'') + '\']'"></a></td>
-            <td data-bind="text: partitionSpec"></td>
-            <td>
-              <a href="#" data-bind="click: function () { window.open(readUrl, '_blank'); return false; }" title="${_('Data')}"><i class="fa fa-th"></i></a> <a href="#" data-bind="click: function () { window.open(browseUrl, '_blank'); return false; }" title="${_('Files')}"><i class="fa fa-file-o"></i></a>
-            </td>
-          </tr>
-        </tbody>
-      </table>
-    </div>
-  </script>
-
-
-  <script type="text/html" id="generic-document-context-template">
-    <div style="width:100%; text-align: center; margin-top: 40px; font-size: 140px; color: #787878;" data-bind="template: { name: 'document-icon-template', data: { document: { isDirectory: type === 'directory', definition: function() { return $data } } } }"></div>
-    <div style="width: 100%; margin-top: 20px; text-align:center">
-      <a style="font-size: 20px;" href="javscript:void(0)" data-bind="text: name, hueLink: link, click: function () { $parents[1].close(); }"></a>
-      <br/>
-      <span data-bind="text: DocumentTypeGlobals[type] || type"></span>
-      <!-- ko if: description -->
-      <br/><br/><span data-bind="text: description"></span>
-      <!-- /ko -->
-    </div>
-  </script>
-
-  <script type="text/html" id="context-document-details">
-    <div class="sql-context-flex-fill" style="overflow: auto;" data-bind="niceScroll">
-      <div style="padding: 8px">
-        <!-- ko if: typeof documentContents() !== 'undefined' && typeof documentContents().snippets !== 'undefined' -->
-        <!-- ko with: documentContents -->
-        <!-- ko foreach: snippets -->
-        <div data-bind="highlight: { value: statement, formatted: true, dialect: type }"></div>
-        <!-- /ko -->
-        <!-- /ko -->
-        <!-- /ko -->
-        <!-- ko if: typeof documentContents() === 'undefined' || typeof documentContents().snippets === 'undefined' -->
-        <div style="width: 100%;" data-bind="template: { name: 'generic-document-context-template', data: details }"></div>
-        <!-- /ko -->
-      </div>
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-popover-template">
-    <div class="hue-popover" data-bind="css: orientationClass, style: { 'left': left() + 'px', 'top': top() + 'px', 'width': width() + 'px', height: height() + 'px' }, resizable: { containment: 'document', handles: resizeHelper.resizableHandles, start: resizeHelper.resizeStart, stop: resizeHelper.resizeStop, resize: resizeHelper.resize }">
-      <div class="hue-popover-arrow" data-bind="style: { 'margin-left': leftAdjust() + 'px',  'margin-top': topAdjust() + 'px' }"></div>
-      <div class="hue-popover-title" style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-right: 30px;">
-        <i class="fa muted" data-bind="css: iconClass" style="margin-top: 3px"></i> <span style="padding-left: 4px;" data-bind="text: title"></span>
-        <div style="position: absolute; right: 6px; top: 8px;">
-          <a class="pointer inactive-action" data-bind="visible: pinEnabled, click: pin"><i class="fa fa-fw fa-thumb-tack"></i></a>
-          <a class="pointer inactive-action" data-bind="click: close"><i class="fa fa-fw fa-times"></i></a>
-        </div>
-      </div>
-      <!-- ko template: 'sql-context-contents' --><!-- /ko -->
-    </div>
-  </script>
-
-  <script type="text/html" id="sql-context-contents">
-    <div class="sql-context-popover-content">
-      <!-- ko with: contents -->
-      <!-- ko if: typeof tabs !== 'undefined' -->
-      <ul class="nav nav-tabs sql-context-tabs" data-bind="foreach: tabs">
-        <li data-bind="click: function () { $parent.activeTab(id); }, css: { 'active' : $parent.activeTab() === id }">
-          <a class="sql-context-tab" data-toggle="tab" data-bind="text: label, attr: { href: '#' + id }"></a>
-        </li>
-      </ul>
-      <div class="sql-context-tab-container" data-bind="foreach: tabs">
-        <div class="sql-context-tab-pane tab-pane" data-bind="visible : $parent.activeTab() === id, attr: { id: id }, css: { 'active' : $parent.activeTab() === id }">
-          <div class="sql-context-flex">
-            <!-- ko with: templateData -->
-            <div class="sql-context-flex-fill" data-bind="visible: loading"><!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko --></div>
-            <!-- ko if: ! loading() && hasErrors() -->
-            <div class="sql-context-flex-fill">
-                <div class="alert">
-                <span data-bind="text: $parent.errorText"></span>
-                <!-- ko if: $parent.enableSampleError && $parent.activeTab() === 'sample' -->
-                <a href="javascript:void(0);" data-bind="click: function(){ huePubSub.publish('sample.error.insert.click', $data); huePubSub.publish('context.popover.hide');}">${_('Insert ')}<span data-bind="text:$parent.title"></span> ${_(' sample query')}</a> ${_('at cursor')}
-                <!-- /ko -->
-                </div>
-            </div>
-            <!-- /ko -->
-            <!-- ko if: ! loading() && ! hasErrors() -->
-            <!-- ko template: { name: $parent.template } --><!-- /ko -->
-            <!-- /ko -->
-            <!-- /ko -->
-            <!-- ko template: { name: 'sql-context-footer', data: $parents[1] } --><!-- /ko -->
-          </div>
-        </div>
-      </div>
-      <!-- /ko -->
-      <!-- ko if: typeof tabs === 'undefined' -->
-      <div class="sql-context-flex-fill" data-bind="visible: loading"><!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko --></div>
-      <!-- ko if: !loading() && hasErrors() -->
-      <div class="sql-context-flex-fill">
-        <div class="alert" data-bind="text: errorText"></div>
-      </div>
-      <!-- /ko -->
-      <!-- ko if: !loading() && !hasErrors() -->
-      <!-- ko template: { name: template } --><!-- /ko -->
-      <!-- /ko -->
-      <!-- ko template: { name: 'sql-context-footer' } --><!-- /ko -->
-      <!-- /ko -->
-      <!-- /ko -->
-    </div>
-  </script>
-
-  <script type="text/javascript">
-    (function () {
-
-      var HALF_SIZE_LIMIT_X = 130;
-      var HALF_SIZE_LIMIT_Y = 100;
-      var HALF_ARROW = 6;
-
-      var preventHide = false;
-
-      var hidePopover = function () {
-        if (! preventHide) {
-          if ($('#sqlContextPopover').length > 0) {
-            ko.cleanNode($('#sqlContextPopover')[0]);
-            $('#sqlContextPopover').remove();
-            $(document).off('click', hideOnClickOutside);
-            huePubSub.publish('context.popover.hidden');
-          }
-        }
-      };
-
-      var hideOnClickOutside = function (event) {
-        if (jQuery.contains(document, event.target) && !$.contains($('#sqlContextPopover')[0], event.target) && ($('.modal')[0].length === 0 || !$.contains($('.modal')[0], event.target))) {
-          hidePopover();
-        }
-      };
-
-      function GenericTabContents(identifierChain, sourceType, defaultDatabase, apiFunction, parent) {
-        var self = this;
-        self.identifierChain = identifierChain;
-        self.sourceType = sourceType;
-        self.defaultDatabase = defaultDatabase;
-        self.apiHelper = ApiHelper.getInstance();
-        self.apiFunction = apiFunction;
-        self.parent = parent;
-
-        self.fetchedData = ko.observable();
-        self.loading = ko.observable(false);
-        self.hasErrors = ko.observable(false);
-      }
-
-      GenericTabContents.prototype.formatAnalysisValue = function (type, val) {
-        if (type === 'last_modified_time' || type === 'transient_lastDdlTime') {
-          return localeFormat(val * 1000);
-        }
-        if (type.toLowerCase().indexOf('size') > -1) {
-          return filesize(val);
-        }
-        return val;
-      };
-
-      GenericTabContents.prototype.fetch = function (callback) {
-        var self = this;
-        if (self.loading()) {
-          return;
-        }
-        self.loading(true);
-        self.hasErrors(false);
-
-        self.apiFunction.bind(self.apiHelper)({
-          sourceType: self.sourceType,
-          identifierChain: self.identifierChain,
-          defaultDatabase: self.defaultDatabase,
-          silenceErrors: true,
-          successCallback: function (data) {
-            if (data.code === 500) {
-              self.loading(false);
-              self.hasErrors(true);
-              if (data.notFound) {
-                self.parent.notFound(data);
-              }
-              return;
-            }
-            if (typeof data.extended_columns !== 'undefined') {
-              data.extended_columns.forEach(function (column) {
-                column.extendedType = column.type.replace(/</g, '&lt;').replace(/>/g, '&lt;');
-                if (column.type.indexOf('<') !== -1) {
-                  column.type = column.type.substring(0, column.type.indexOf('<'));
-                }
-              });
-            }
-            if (typeof data.properties !== 'undefined') {
-              data.properties.forEach(function (property) {
-                if (property.col_name.toLowerCase() === 'view original text:') {
-                  data.viewSql = ko.observable();
-                  data.loadingViewSql = ko.observable(true);
-                  ApiHelper.getInstance().formatSql(property.data_type).done(function (formatResponse) {
-                    if (formatResponse.status == 0) {
-                      data.viewSql(formatResponse.formatted_statements);
-                    } else {
-                      data.viewSql(property.data_type);
-                    }
-                  }).fail(function () {
-                    data.viewSql(property.data_type);
-                  }).always(function () {
-                    data.loadingViewSql(false);
-                  })
-                }
-              })
-            }
-            self.fetchedData(data);
-            self.loading(false);
-            if (typeof callback === 'function') {
-              callback(data);
-            }
-          },
-          errorCallback: function () {
-            self.loading(false);
-            self.hasErrors(true);
-          }
-        });
-      };
-
-
-      function TableAndColumnContextTabs(data, sourceType, defaultDatabase, isColumn, isComplex) {
-        var self = this;
-        self.tabs = ko.observableArray();
-        self.disposals = [];
-
-        var apiHelper = ApiHelper.getInstance();
-
-        self.columns = new GenericTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchAutocomplete, self);
-        self.columnDetails = new GenericTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchAutocomplete, self);
-        self.tableDetails = new GenericTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchAnalysis, self);
-        self.sample = new GenericTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchSamples, self);
-        self.analysis = new GenericTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchAnalysis, self);
-        self.partitions = new GenericTabContents(data.identifierChain, sourceType, defaultDatabase, apiHelper.fetchPartitions, self);
-
-        self.hasErrors = false;
-        self.isTable = !isColumn && !isComplex;
-
-        self.title = data.identifierChain[data.identifierChain.length - 1].name;
-
-        self.activeTab = ko.observable();
-
-        self.activeTab.subscribe(function (newValue) {
-          if (newValue === 'sample') {
-            if (typeof self.sample.fetchedData() === 'undefined') {
-              if (!isComplex) {
-                self.sample.fetch(self.initializeSamplesTable);
-              } else {
-                var data = self.columnDetails.fetchedData();
-                var rows = [];
-                data.sample.forEach(function (sample) {
-                  rows.push([sample]);
-                });
-                self.sample.fetchedData({
-                  headers: [ data.name || self.title ],
-                  rows: rows
-                });
-                self.initializeSamplesTable(self.sample.fetchedData());
-              }
-            }
-          } else if (newValue === 'complexDetails') {
-            if (typeof self.columnDetails.fetchedData() === 'undefined') {
-              self.columnDetails.fetch(function (data) {
-                if (data.sample) {
-                  self.tabs.push({
-                    id: 'sample',
-                    label: '${ _("Sample") }',
-                    template: 'sql-context-table-and-column-sample',
-                    templateData: self.sample,
-                    errorText: '${ _("There was a problem loading the samples.") }'
-                  });
-                }
-              })
-            }
-          } else if (!self.hasErrors && typeof self[newValue].fetchedData() === 'undefined') {
-            self[newValue].fetch();
-          }
-        });
-
-        if (isColumn) {
-          self.tabs.push({
-            id: 'columnDetails',
-            label: '${ _("Details") }',
-            template: 'sql-context-column-details',
-            templateData: self.columnDetails,
-            errorText: '${ _("There was a problem loading the column details.") }',
-            isColumn: true
-          });
-          self.activeTab('columnDetails');
-        } else if (isComplex) {
-          self.tabs.push({
-            id: 'complexDetails',
-            label: '${ _("Details") }',
-            template: 'sql-context-complex-details',
-            templateData: self.columnDetails,
-            errorText: '${ _("There was a problem loading the details.") }',
-            isColumn: false
-          });
-          self.activeTab('complexDetails');
-        } else {
-          self.tabs.push({
-            id: 'columns',
-            label: '${ _("Columns") }',
-            template: 'sql-context-columns',
-            templateData: self.columns,
-            errorText: '${ _("There was a problem loading the columns.") }',
-            isColumn: false
-          });
-          self.tabs.push({
-            id: 'tableDetails',
-            label: '${ _("Details") }',
-            template: 'sql-context-table-details',
-            templateData: self.tableDetails,
-            errorText: '${ _("There was a problem loading the table details.") }',
-            isColumn: false
-          });
-          self.activeTab('columns');
-        }
-
-        if (!isComplex) {
-          self.tabs.push({
-            id: 'sample',
-            label: '${ _("Sample") }',
-            template: 'sql-context-table-and-column-sample',
-            templateData: self.sample,
-            errorText: '${ _("There was a problem loading the samples.") }',
-            isColumn: isColumn,
-            title: self.title,
-            enableSampleError: true
-          });
-        }
-
-        if (isColumn) {
-          self.columnDetails.fetch(function (data) {
-            self.tabs.push({
-              id: 'analysis',
-              label: '${ _("Analysis") }',
-              template: 'sql-context-column-analysis',
-              templateData: self.analysis,
-              errorText: '${ _("There was a problem loading the column analysis.") }',
-              isColumn: true
-            });
-          });
-        } else if (!isComplex) {
-          self.tableDetails.fetch(function (data) {
-            if (data.partition_keys.length === 0) {
-              self.tabs.push({
-                id: 'analysis',
-                label: '${ _("Analysis") }',
-                template: 'sql-context-table-analysis',
-                templateData: self.analysis,
-                errorText: '${ _("There was a problem loading the table analysis.") }',
-                isColumn: false
-              });
-            } else if (data.partition_keys.length > 0) {
-              self.tabs.push({
-                id: 'partitions',
-                label: '${ _("Partitions") }',
-                template: 'sql-context-table-partitions',
-                templateData: self.partitions,
-                errorText: '${ _("There was a problem loading the table partitions.") }',
-                isColumn: false
-              });
-            }
-          });
-        }
-
-        var sampleInterval = window.setInterval(function () {
-          if (self.activeTab() !== 'sample') {
-            return;
-          }
-          var $t = $('.samples-table');
-          if ($t.length === 0) {
-            return;
-          }
-
-          $t.parents('.dataTables_wrapper').getNiceScroll().resize();
-        }, 300);
-
-        self.disposals.push(function () {
-          window.clearInterval(sampleInterval);
-        });
-
-        var performScrollToColumn = function (colName) {
-          self.activeTab('sample');
-          window.setTimeout(function () {
-            var _t = $('.samples-table');
-            var _col = _t.find("th").filter(function () {
-              return $.trim($(this).text()).endsWith(colName);
-            });
-            _t.find(".columnSelected").removeClass("columnSelected");
-            var _colSel = _t.find("tr th:nth-child(" + (_col.index() + 1) + ")");
-            if (_colSel.length > 0) {
-              _t.find("tr td:nth-child(" + (_col.index() + 1) + ")").addClass("columnSelected");
-              _t.parent().animate({
-                scrollLeft: _colSel.position().left + _t.parent().scrollLeft() - _t.parent().offset().left - 30
-              }, 300, function(){
-                _t.data('scrollToCol', _col.index());
-                _t.data('scrollToRow', null);
-                _t.data('scrollAnimate', true);
-                _t.data('scrollInPopover', true);
-                _t.parent().trigger('scroll');
-              });
-            }
-          }, 0);
-        };
-
-        var scrollPubSub = huePubSub.subscribe('context.popover.scroll.to.column', function (colName) {
-          if (typeof self.sample.fetchedData() === 'undefined') {
-            self.activeTab('sample');
-            self.sample.fetch(function (data) {
-              self.initializeSamplesTable(data);
-              window.setTimeout(function () {
-                performScrollToColumn(colName);
-              }, 0);
-            });
-          } else {
-            performScrollToColumn(colName);
-          }
-        });
-        self.disposals.push(function () {
-          scrollPubSub.remove();
-        });
-
-        apiHelper.identifierChainToPath({
-          sourceType: sourceType,
-          defaultDatabase: defaultDatabase,
-          identifierChain: data.identifierChain
-        }, function (path) {
-          var showInAssistPubSub = huePubSub.subscribe('context.popover.show.in.assist', function () {
-            huePubSub.publish('assist.db.highlight', {
-              sourceType: sourceType,
-              path: path
-            });
-          });
-          self.disposals.push(function () {
-            showInAssistPubSub.remove();
-          })
-        });
-
-        self.initializeSamplesTable = function (data) {
-          window.setTimeout(function () {
-            var $t = $('.samples-table');
-
-            if ($t.parent().hasClass('dataTables_wrapper')) {
-              if ($t.parent().data('scrollFnDt')) {
-                $t.parent().off('scroll', $t.parent().data('scrollFnDt'));
-              }
-              $t.unwrap();
-              if ($t.children('tbody').length > 0) {
-                $t.children('tbody').empty();
-              } else {
-                $t.children('tr').remove();
-              }
-              $t.data('isScrollAttached', null);
-              $t.data('data', []);
-            }
-            var dt = $t.hueDataTable({
-              i18n: {
-                NO_RESULTS: "${_('No results found.')}",
-                OF: "${_('of')}"
-              },
-              fnDrawCallback: function (oSettings) {
-              },
-              scrollable: '.dataTables_wrapper',
-              forceInvisible: 10
-            });
-
-            $t.parents('.dataTables_wrapper').height($t.parents('.sample-scroll').parent().height());
-
-            $t.jHueTableExtender2({
-              fixedHeader: true,
-              fixedFirstColumn: true,
-              fixedFirstColumnTopMargin: -2,
-              headerSorting: false,
-              includeNavigator: false,
-              parentId: 'sampleTab',
-              noSort: true,
-              mainScrollable: '.sample-scroll > .dataTables_wrapper'
-            });
-
-            huePubSub.subscribe('context.popover.resized', function () {
-              $t.parent().height($t.parents('.context-sample-container').height());
-            });
-
-            self.disposals.push(function () {
-              if ($t.data('plugin_jHueTableExtender2')) {
-                $t.data('plugin_jHueTableExtender2').destroy();
-              }
-              huePubSub.removeAll('context.popover.resized');
-            });
-
-            hueUtils.initNiceScroll($t.parents('.dataTables_wrapper'));
-
-            if (data && data.rows) {
-              var _tempData = [];
-              $.each(data.rows, function (index, row) {
-                var _row = row.slice(0); // need to clone the array otherwise it messes with the caches
-                _row.unshift(index + 1);
-                _tempData.push(_row);
-              });
-              if (_tempData.length > 0) {
-                dt.fnAddData(_tempData);
-              }
-            }
-          }, 0);
-        };
-      }
-
-      TableAndColumnContextTabs.prototype.dispose = function () {
-        var self = this;
-        while (self.disposals.length) {
-          self.disposals.pop()();
-        }
-      };
-
-      TableAndColumnContextTabs.prototype.notFound = function (data) {
-        var self = this;
-        self.hasErrors = true;
-        var message;
-        if (data.error && data.error.indexOf('10001]:') !== -1) {
-          message = data.error.substring(data.error.indexOf('10001]:') + 8);
-        } else {
-          message = '${ _("Could not load") }' + ': ' + self.title
-        }
-        self.tabs([{
-          id: 'notFound',
-          label: '${ _("Details") }',
-          templateData: {
-            loading: ko.observable(false),
-            hasErrors: ko.observable(false),
-            message: message
-          },
-          template: 'sql-context-table-and-column-unknown',
-          title: self.title
-        }]);
-        self.activeTab('notFound');
-      };
-
-      TableAndColumnContextTabs.prototype.refetchSamples = function () {
-        var self = this;
-        self.sample.fetch(self.initializeSamplesTable);
-      };
-
-      function DatabaseContextTabs(data, sourceType, defaultDatabase) {
-        var self = this;
-        self.dbComment = ko.observable('');
-        var dbName = data.identifierChain[data.identifierChain.length - 1].name;
-        $.getJSON('/metastore/databases/' + dbName + '/metadata', function (data) {
-          if (data && data.status == 0 && data.data.comment) {
-              self.dbComment(data.data.comment);
-          }
-        });
-        self.tabs = [
-          { id: 'details', label: '${ _("Details") }', comment : self.dbComment, template: 'sql-context-database-details', templateData: new GenericTabContents(data.identifierChain, sourceType, defaultDatabase, ApiHelper.getInstance().fetchAutocomplete) }
-        ];
-        self.activeTab = ko.observable('details');
-      }
-
-      function AsteriskData(data, sourceType, defaultDatabase) {
-        var self = this;
-        self.loading = ko.observable(true);
-        self.hasErrors = ko.observable(false);
-        self.columns = [];
-
-        self.selectedColumns = ko.pureComputed(function () {
-          return self.columns.filter(function (column) {
-            return column.selected();
-          });
-        });
-
-        self.expand = function () {
-          var colsToExpand = self.selectedColumns().length === 0 ? self.columns : self.selectedColumns();
-          var colIndex = {};
-          var colsTableMap = {};
-          self.columns.forEach(function (col) {
-            if (colsTableMap[col.name]) {
-              colsTableMap[col.name].push(col.table);
-            }
-            else {
-              colsTableMap[col.name] = [col.table];
-            }
-          });
-          colsToExpand.forEach(function (col) {
-            if (colIndex[col.name]) {
-              colIndex[col.name]++;
-            } else {
-              colIndex[col.name] = 1;
-            }
-          });
-          Object.keys(colIndex).forEach(function (name) {
-            if (colIndex[name] === 1 && colsTableMap[name].length === 1) {
-              delete colIndex[name];
-            }
-          });
-          var sqlAutocompleter = new SqlAutocompleter2({
-            snippet: {
-              type: function () {
-                return sourceType;
-              }
-            }
-          });
-          huePubSub.publish('ace.replace', {
-            location: data.location,
-            text: $.map(colsToExpand, function (column) {
-              if (column.tableAlias) {
-                return sqlAutocompleter.backTickIfNeeded(column.tableAlias) + '.' + sqlAutocompleter.backTickIfNeeded(column.name);
-              }
-              if (colIndex[column.name]) {
-                return sqlAutocompleter.backTickIfNeeded(column.table) + '.' + sqlAutocompleter.backTickIfNeeded(column.name);
-              }
-              return sqlAutocompleter.backTickIfNeeded(column.name)
-            }).join(', ')
-          });
-          huePubSub.publish('context.popover.hide');
-        };
-
-        var apiHelper = ApiHelper.getInstance();
-        var deferrals = [];
-        data.tables.forEach(function (table) {
-          if (table.identifierChain) {
-            var fetchDeferred = $.Deferred();
-            deferrals.push(fetchDeferred);
-            apiHelper.fetchAutocomplete({
-              sourceType: sourceType,
-              defaultDatabase: defaultDatabase,
-              identifierChain: table.identifierChain,
-              successCallback: function (data) {
-                if (typeof data.extended_columns !== 'undefined') {
-                  data.extended_columns.forEach(function (column) {
-                    column.extendedType = column.type.replace(/</g, '&lt;').replace(/>/g, '&lt;');
-                    if (column.type.indexOf('<') !== -1) {
-                      column.type = column.type.substring(0, column.type.indexOf('<'));
-                    }
-                    column.selected = ko.observable(false);
-                    column.table = table.identifierChain[table.identifierChain.length - 1].name;
-                    if (table.alias) {
-                      column.tableAlias = table.alias
-                    }
-                  });
-                }
-                self.columns = self.columns.concat(data.extended_columns);
-                fetchDeferred.resolve();
-              },
-              silenceErrors: true,
-              errorCallback: fetchDeferred.reject
-            })
-          }
-        });
-
-        if (deferrals.length === 0) {
-          self.loading(false);
-        }
-        $.when.apply($, deferrals).done(function () {
-          self.loading(false);
-        }, function () {
-          if (self.columns.length === 0) {
-            self.hasErrors(true);
-          }
-        });
-      }
-
-      function AsteriskContextTabs(data, sourceType, defaultDatabase) {
-        var self = this;
-        self.data = new AsteriskData(data, sourceType, defaultDatabase);
-
-        self.tabs = [
-          { id: 'details', label: '${ _("Details") }', template: 'sql-context-asterisk-details', templateData: self.data }
-        ];
-        self.activeTab = ko.observable('details');
-      }
-
-      function HdfsContextTabs(data) {
-        var self = this;
-
-        self.disposals = [];
-
-        // TODO: Update Ace token with selected path
-        self.data = ko.observable({
-          details: data,
-          loading: ko.observable(false),
-          hasErrors: ko.observable(false),
-          selectedPath: ko.observable(data.path)
-        });
-
-        var showInFileBrowserPubSub = huePubSub.subscribe('context.popover.open.in.file.browser', function () {
-          window.open((data.path.indexOf('/') === 0 ? '/filebrowser/#' : '/filebrowser/#/') + data.path, '_blank');
-        });
-
-        self.disposals.push(function () {
-          showInFileBrowserPubSub.remove();
-        });
-
-        var replaceInEditorPubSub = huePubSub.subscribe('context.popover.replace.in.editor', function () {
-          huePubSub.publish('ace.replace', {
-            location: data.location,
-            text: self.data().selectedPath()
-          });
-        });
-        self.disposals.push(function () {
-          replaceInEditorPubSub.remove();
-        });
-
-        self.tabs = [
-          { id: 'details', label: '${ _("Details") }', template: 'sql-context-hdfs-details', templateData: self.data }
-        ];
-        self.activeTab = ko.observable('details');
-      }
-
-      HdfsContextTabs.prototype.dispose = function () {
-        var self = this;
-        while (self.disposals.length) {
-          self.disposals.pop()();
-        }
-      };
-
-      function FunctionContextTabs(data, sourceType) {
-        var self = this;
-        self.func = ko.observable({
-          details: SqlFunctions.findFunction(sourceType, data.function),
-          loading: ko.observable(false),
-          hasErrors: ko.observable(false)
-        });
-
-        self.tabs = [
-          { id: 'details', label: '${ _("Details") }', template: 'sql-context-function-details', templateData: self.func }
-        ];
-        self.activeTab = ko.observable('details');
-      }
-
-      function DocumentContext(data) {
-        var self = this;
-
-        // Adapt some details to a common format, the global search endpoint has different structure than the docs one
-        self.details = {
-          type: data.type || data.doc_type,
-          name: data.name || data.hue_name,
-          link: data.absoluteUrl || data.link,
-          description: data.description || data.hue_description
-        };
-        self.data = data;
-        self.loading = ko.observable(true);
-        self.hasErrors = ko.observable(false);
-        self.errorText = ko.observable();
-        self.showInAssistEnabled = false; // TODO: Enable for documents
-        self.template = 'context-document-details';
-
-        self.documentContents = ko.observable();
-        self.loadDocument();
-      }
-
-      DocumentContext.prototype.loadDocument = function () {
-        var self = this;
-        self.hasErrors(false);
-        self.loading(true);
-        ApiHelper.getInstance().fetchDocument({
-          uuid: self.data.uuid,
-          fetchContents: true,
-          silenceErrors: true
-        }).done(function (response) {
-          self.documentContents(response.data);
-          self.loading(false);
-        }).fail(function (errorMessage) {
-          self.loading(false);
-          self.hasErrors(false); // Allows us to revert to a generic document panel in case it can't fetch it.
-        })
-      };
-
-      function ResizeHelper (orientation, leftAdjust, topAdjust) {
-        var self = this;
-
-        var apiHelper = ApiHelper.getInstance();
-
-        var originalMidX, originalWidth, originalRightX, originalLeftX, originalMidY, originalHeight, originalTopY, originalBottomY;
-        var rightX, leftX, leftDiff, rightDiff, topY, bottomY, topDiff, bottomDiff;
-        var redrawHeaders = false;
-
-        window.setTimeout(function () {
-          var offset = $('.hue-popover').offset();
-          if (orientation === 'right') {
-            offset.left -= 5;
-          } else if (orientation === 'bottom') {
-            offset.top -= 5;
-          }
-          originalHeight = $('.hue-popover').height();
-          originalWidth = $('.hue-popover').width();
-          originalMidX = offset.left + originalWidth / 2;
-          originalMidY = offset.top + originalHeight / 2;
-          originalLeftX = offset.left;
-          originalRightX = offset.left + originalWidth;
-          originalTopY = offset.top;
-          originalBottomY = offset.top + originalHeight;
-        }, 0);
-
-        self.saveSize = function () {
-          apiHelper.setInTotalStorage('assist', 'popover.size', {
-            width: $('.hue-popover').width(),
-            height: $('.hue-popover').height()
-          });
-        };
-
-        self.resizeStart = function (event, ui) {
-          preventHide = true;
-        };
-
-        self.resizeStop = function (event, ui) {
-          if (redrawHeaders) {
-            huePubSub.publish('table.extender.redraw', 'sampleTab');
-            redrawHeaders = false;
-          }
-
-          huePubSub.publish('context.popover.resized');
-
-          // Delay or it will close the popover when releasing at the window borders
-          window.setTimeout(function () {
-            preventHide = false;
-          }, 300);
-
-          self.saveSize();
-        };
-
-        var resizeTopBottomHorizontal = function (event, ui) {
-          leftX = ui.position.left;
-          rightX = ui.position.left + ui.size.width;
-
-          if (rightX < originalMidX + HALF_SIZE_LIMIT_X) {
-            ui.size.width = originalMidX + HALF_SIZE_LIMIT_X - ui.position.left;
-            rightX = ui.position.left + ui.size.width;
-            $('.hue-popover').css('width', ui.size.width + 'px');
-          }
-
-          if (leftX > originalMidX - HALF_SIZE_LIMIT_X) {
-            ui.position.left = originalMidX - HALF_SIZE_LIMIT_X;
-            ui.size.width = ui.originalSize.width - (ui.position.left - ui.originalPosition.left);
-            leftX = ui.position.left;
-            rightX = ui.position.left + ui.size.width;
-            $('.hue-popover').css('left', ui.position.left + 'px');
-            $('.hue-popover').css('width', ui.size.width + 'px');
-          }
-
-          leftDiff = originalLeftX - leftX;
-          rightDiff = originalRightX - rightX;
-          $('.hue-popover-arrow').css('margin-left', (leftDiff + rightDiff) / 2 + leftAdjust() + 'px');
-        };
-
-        var resizeLeftRightVertical = function (event, ui) {
-          if (!redrawHeaders && ui.originalPosition.top !== ui.position.top) {
-            redrawHeaders = true;
-            huePubSub.publish('table.extender.hide', 'sampleTab');
-          }
-          topY = ui.position.top;
-          bottomY = ui.position.top + ui.size.height;
-
-          if (bottomY < originalMidY + HALF_SIZE_LIMIT_Y) {
-            ui.size.height = originalMidY + HALF_SIZE_LIMIT_Y - ui.position.top;
-            bottomY = ui.position.top + ui.size.height;
-            $('.hue-popover').css('height', ui.size.height + 'px');
-          }
-
-          if (topY > originalMidY - HALF_SIZE_LIMIT_Y) {
-            ui.position.top = originalMidY - HALF_SIZE_LIMIT_Y;
-            ui.size.height = ui.originalSize.height - (ui.position.top - ui.originalPosition.top);
-            topY = ui.position.top;
-            bottomY = ui.position.top + ui.size.height;
-            $('.hue-popover').css('top', ui.position.top + 'px');
-            $('.hue-popover').css('height', ui.size.height + 'px');
-          }
-
-          topDiff = originalTopY - topY;
-          bottomDiff = originalBottomY - bottomY;
-          $('.hue-popover-arrow').css('margin-top', (topDiff + bottomDiff) / 2 + topAdjust() + 'px');
-        };
-
-        switch(orientation) {
-          case 'top':
-            self.resizableHandles = "w, nw, n, ne, e";
-            self.resize = function (event, ui) {
-              resizeTopBottomHorizontal(event, ui);
-              // TODO: Implement resize height limits when popover is above
-            };
-            break;
-          case 'right':
-            self.resizableHandles = "n, ne, e, se, s";
-            self.resize = function (event, ui) {
-              resizeLeftRightVertical(event, ui);
-              if (ui.size.width < 350) {
-                ui.size.width = 350;
-                $('.hue-popover').css('width', 350 + 'px');
-              }
-            };
-            break;
-          case 'bottom':
-            self.resizableHandles = "e, se, s, sw, w";
-            self.resize = function (event, ui) {
-              resizeTopBottomHorizontal(event, ui);
-              if (ui.size.height < 200) {
-                ui.size.height = 200;
-                $('.hue-popover').css('height', 200 + 'px');
-              }
-            };
-            break;
-          case 'left':
-            self.resizableHandles = "s, sw, w, nw, n";
-            self.resize = function (event, ui) {
-              resizeLeftRightVertical(event, ui);
-              // TODO: Implement resize width limits when popover is on the left
-            };
-            break;
-        }
-      }
-
-      function SqlContextPopoverViewModel(params) {
-        var self = this;
-        self.disposals = [];
-
-        var apiHelper = ApiHelper.getInstance();
-
-        self.left = ko.observable(0);
-        self.top = ko.observable(0);
-
-        self.showInAssistEnabled = typeof params.showInAssistEnabled !== 'undefined' ? params.showInAssistEnabled : true;
-
-        var popoverSize = apiHelper.getFromTotalStorage('assist', 'popover.size', {
-          width: 450,
-          height: 400
-        });
-
-        self.width = ko.observable(popoverSize.width);
-        self.height = ko.observable(popoverSize.height);
-
-        self.leftAdjust = ko.observable(0);
-        self.topAdjust = ko.observable(0);
-        self.data = params.data;
-        self.sourceType = params.sourceType;
-        self.defaultDatabase = params.defaultDatabase;
-        self.close = hidePopover;
-        var orientation = params.orientation || 'bottom';
-        self.contents = null;
-        self.resizeHelper = new ResizeHelper(orientation, self.leftAdjust, self.topAdjust);
-
-        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;
-
-          var detectMoveInterval = window.setInterval(function () {
-            currentSourceOffset = $source.offset();
-            if (currentSourceOffset.left !== originalSourceOffset.left || currentSourceOffset.top !== originalSourceOffset.top) {
-              hidePopover();
-            }
-          }, 200);
-
-          self.disposals.push(function () {
-            window.clearInterval(detectMoveInterval);
-          });
-        }
-
-        var windowWidth = $(window).width();
-        var fitHorizontally = function () {
-          var left = params.source.left + Math.round((params.source.right - params.source.left) / 2) - (self.width() / 2);
-          if (left + self.width() > windowWidth - 10) {
-            self.leftAdjust(left + self.width() - windowWidth + 5);
-            left = windowWidth - self.width() - 10;
-          } else if (left < 10) {
-            self.leftAdjust(left - 10 - HALF_ARROW);
-            left = 10;
-          } else {
-            self.leftAdjust(-HALF_ARROW);
-          }
-          self.left(left);
-        };
-
-        var windowHeight = $(window).height();
-        var fitVertically = function () {
-          var top = params.source.top + Math.round((params.source.bottom - params.source.top) / 2) - (self.height() / 2);
-          if (top + self.height() > windowHeight - 10) {
-            self.topAdjust(top + self.height() - windowHeight + 5);
-            top = windowHeight - self.height() - 10;
-          } else if (top < 10) {
-            self.topAdjust(top - 10 - HALF_ARROW);
-            top = 10;
-          } else {
-            self.topAdjust(-HALF_ARROW);
-          }
-          self.top(top);
-        };
-
-        switch (orientation) {
-          case 'top':
-            fitHorizontally();
-            self.top(params.source.top - self.height());
-            break;
-          case 'right':
-            fitVertically();
-            self.left(params.source.right);
-            break;
-          case 'bottom':
-            fitHorizontally();
-            self.top(params.source.bottom);
-            break;
-          case 'left':
-            fitVertically();
-            self.left(params.source.left - self.width());
-        }
-
-        self.isDatabase = params.data.type === 'database';
-        self.isTable = params.data.type === 'table';
-        self.isColumn = params.data.type === 'column';
-        self.isComplex = params.data.type === 'complex';
-        self.isFunction = params.data.type === 'function';
-        self.isHdfs = params.data.type === 'hdfs';
-        self.isAsterisk = params.data.type === 'asterisk';
-        self.isView = params.data.type === 'view';
-        self.isDocument = params.data.type.toLowerCase() === 'hue';
-
-        if ((self.isColumn || self.isComplex) && self.data.tables && self.data.tables.length > 0) {
-          var identifierChain = self.data.identifierChain;
-          var foundTable = $.grep(self.data.tables, function (table) {
-            return hueUtils.equalIgnoreCase(table.alias, identifierChain[0].name) ||
-                    (table.identifierChain && hueUtils.equalIgnoreCase(table.identifierChain[table.identifierChain.length - 1].name, identifierChain[0].name));
-          });
-          if (foundTable.length === 1 && foundTable.identifierChain) {
-            identifierChain.shift();
-            identifierChain = foundTable.identifierChain.concat(identifierChain);
-            delete self.data.tables;
-          } else if (self.data.tables.length === 1 && self.data.tables[0].identifierChain) {
-            identifierChain = self.data.tables[0].identifierChain.concat(identifierChain);
-            delete self.data.tables;
-          }
-          self.data.identifierChain = identifierChain
-        }
-
-        self.pinEnabled = params.pinEnabled && !self.isFunction && !self.isAsterisk && !self.isHdfs;
-
-        if (self.isTable || self.isView) {
-          self.title = $.map(self.data.identifierChain, function (identifier) { return identifier.name; }).join('.');
-          if (self.title.indexOf('.') === -1) {
-            self.title = self.defaultDatabase + '.' + self.title;
-          }
-        }
-
-        if (self.isDatabase) {
-          self.contents = new DatabaseContextTabs(self.data, self.sourceType, self.defaultDatabase);
-          self.title = self.data.identifierChain[self.data.identifierChain.length - 1].name;
-          self.iconClass = 'fa-database';
-        } else if (self.isTable) {
-          self.contents = new TableAndColumnContextTabs(self.data, self.sourceType, self.defaultDatabase, false, false);
-          self.iconClass = 'fa-table'
-        } else if (self.isView) {
-          self.contents = new TableAndColumnContextTabs(self.data, self.sourceType, self.defaultDatabase, false, false);
-          self.iconClass = 'fa-eye'
-        } else if (self.isComplex) {
-          self.contents = new TableAndColumnContextTabs(self.data, self.sourceType, self.defaultDatabase, false, true);
-          self.title = self.data.identifierChain[self.data.identifierChain.length - 1].name;
-          self.iconClass = 'fa-columns'
-        } else if (self.isColumn) {
-          self.contents = new TableAndColumnContextTabs(self.data, self.sourceType, self.defaultDatabase, true, false);
-          if (self.data.identifierChain.length > 1) {
-            self.title = self.data.identifierChain[self.data.identifierChain.length - 2].name + '.' + self.data.identifierChain[self.data.identifierChain.length - 1].name;
-          } else {
-            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.sourceType);
-          self.title = self.data.function;
-          self.iconClass = 'fa-superscript'
-        } else if (self.isHdfs) {
-          self.contents = new HdfsContextTabs(self.data);
-          self.title = self.data.path;
-          self.iconClass = 'fa-folder-o'
-        } else if (self.isAsterisk) {
-          self.contents = new AsteriskContextTabs(self.data, self.sourceType, self.defaultDatabase);
-          self.title = '*';
-          self.iconClass = 'fa-table';
-        } else if (self.isDocument) {
-          self.contents = new DocumentContext(self.data.definition);
-          self.title = self.data.definition.name;
-          self.iconClass = 'fa-file-o';
-        } else {
-          self.title = '';
-          self.iconClass = 'fa-info'
-        }
-        self.orientationClass = 'hue-popover-' + orientation;
-
-        if ((self.isDatabase || self.isTable || self.isView) && self.data.identifierChain) {
-          apiHelper.identifierChainToPath({
-            sourceType: self.sourceType,
-            identifierChain: self.data.identifierChain,
-            defaultDatabase: self.defaultDatabase
-          }, function (path) {
-
-            var showInMetastorePubSub = huePubSub.subscribe('context.popover.open.in.metastore', function (type) {
-              if (IS_HUE_4) {
-                huePubSub.publish('open.link', '/metastore/table' + (type === 'table' ? '/' : 's/') + path.join('/'));
-                huePubSub.publish('context.popover.hide');
-              } else {
-                window.open('/metastore/table' + (type === 'table' ? '/' : 's/') + path.join('/'), '_blank');
-              }
-            });
-            self.disposals.push(function () {
-              showInMetastorePubSub.remove();
-            });
-            % if HAS_SQL_ENABLED.get():
-            var openInDashboardPubSub = huePubSub.subscribe('context.popover.open.in.dashboard', function () {
-              if (IS_HUE_4) {
-                huePubSub.publish('open.link', '/hue/dashboard/browse/' + path.join('.') + '?engine=' + self.sourceType);
-                huePubSub.publish('context.popover.hide');
-              } else {
-                window.open('/hue/dashboard/browse/' + path.join('.') + '?engine=' + self.sourceType, '_blank');
-              }
-            });
-            self.disposals.push(function () {
-              openInDashboardPubSub.remove();
-            });
-            % endif
-          });
-        }
-
-        if (params.delayedHide) {
-          var hideTimeout = -1;
-          var onLeave = function () {
-            hideTimeout = window.setTimeout(function () {
-              $('.hue-popover').fadeOut(200, function () {
-                hidePopover();
-              })
-            }, 1000);
-          };
-
-          var onEnter = function () {
-            window.clearTimeout(hideTimeout);
-          };
-
-          $(params.delayedHide).add($('.hue-popover')).on('mouseleave', onLeave).on('mouseenter', onEnter);
-
-          var keepPopoverOpenOnClick = function () {
-            window.clearTimeout(hideTimeout);
-            $(params.delayedHide).add($('.hue-popover')).off('mouseleave', onLeave).off('mouseenter', onEnter);
-          };
-
-          $('.hue-popover').on('click', keepPopoverOpenOnClick);
-
-          self.disposals.push(function () {
-            $(params.delayedHide).add($('.hue-popover')).off('mouseleave', onLeave).off('mouseenter', onEnter);
-            $('.hue-popover').off('click', keepPopoverOpenOnClick);
-          });
-        }
-
-        var closeOnEsc = function (e) {
-          if (e.keyCode === 27) {
-            hidePopover();
-          }
-        };
-
-        $(document).on('keyup', closeOnEsc);
-
-        self.disposals.push(function () {
-          $(document).off('keyup', closeOnEsc);
-        });
-
-        window.setTimeout(function() {
-          $(document).on('click', hideOnClickOutside);
-        }, 0);
-
-        self.disposals.push(function () {
-          $(document).off('click', hideOnClickOutside);
-        })
-      }
-
-      SqlContextPopoverViewModel.prototype.dispose = function() {
-        var self = this;
-        while (self.disposals.length) {
-          self.disposals.pop()();
-        }
-
-        if(self.contents && self.contents.dispose) {
-          self.contents.dispose();
-        }
-        huePubSub.publish('context.popover.dispose');
-      };
-
-      SqlContextPopoverViewModel.prototype.pin = function () {
-        var self = this;
-        hidePopover();
-        if (typeof self.contents.sample !== 'undefined') {
-          self.contents.sample.fetchedData(undefined);
-        }
-        huePubSub.publish('sql.context.pin', self);
-        if (self.contents.activeTab() === 'sample') {
-          self.contents.refetchSamples();
-        }
-      };
-
-      ko.components.register('sql-context-popover', {
-        viewModel: SqlContextPopoverViewModel,
-        template: { element: 'sql-context-popover-template' }
-      });
-
-      huePubSub.subscribe('context.popover.hide', hidePopover);
-
-      huePubSub.subscribe('context.popover.show', function (details) {
-        hidePopover();
-        var $sqlContextPopover = $('<div id="sqlContextPopover" data-bind="component: { name: \'sql-context-popover\', params: $data }" />');
-        $('body').append($sqlContextPopover);
-        ko.applyBindings(details, $sqlContextPopover[0]);
-        huePubSub.publish('context.popover.shown');
-      });
-
-      var SqlContextContentsGlobalSearch = function (params) {
-        var self = this;
-        self.contents = undefined;
-
-        self.disposals = [];
-
-        self.showInAssistEnabled = true;
-
-        self.isDatabase = params.data.type.toLowerCase() === 'database';
-        self.isTable = params.data.type.toLowerCase() === 'table';
-        self.isColumn = params.data.type.toLowerCase() === 'field';
-        self.isView = params.data.type.toLowerCase() === 'view';
-        self.isDocument = params.data.type.toLowerCase() === 'hue';
-
-        // TODO: Handle HDFS, Complex and Function ?
-        self.isHdfs = false;
-        self.isAsterisk = false;
-        self.isComplex = false;
-        self.isFunction = false;
-
-        var adaptedData = { identifierChain: [] };
-
-        var path = params.data.originalName.split('.');
-        path.forEach(function (part) {
-          adaptedData.identifierChain.push({ name: part });
-        });
-
-        var metastorePubSub = huePubSub.subscribe('context.popover.open.in.metastore', function () {
-          huePubSub.publish('open.link', '/metastore/table' + (self.isTable ? '/' : 's/') + path.join('/'));
-          params.globalSearch.close();
-        });
-
-        self.disposals.push(function () {
-          metastorePubSub.remove();
-        });
-
-
-        if (self.isDatabase) {
-          self.contents = new DatabaseContextTabs(adaptedData, params.data.sourceType.toLowerCase(), 'default');
-        } else if (self.isTable) {
-          self.contents = new TableAndColumnContextTabs(adaptedData, params.data.sourceType.toLowerCase(), 'default', false, false);
-        } else if (self.isView) {
-          self.contents = new TableAndColumnContextTabs(adaptedData, params.data.sourceType.toLowerCase(), 'default', false, false);
-        } else if (self.isColumn) {
-          self.contents = new TableAndColumnContextTabs(adaptedData, params.data.sourceType.toLowerCase(), 'default', true, false);
-        } else if (self.isDocument) {
-          self.contents = new DocumentContext(params.data);
-        }
-      };
-
-      SqlContextContentsGlobalSearch.prototype.dispose = function () {
-        var self = this;
-        while (self.disposals.length) {
-          self.disposals.pop()();
-        }
-        if (self.contents && self.contents.dispose) {
-          self.contents.dispose();
-        }
-
-        huePubSub.publish('context.popover.dispose');
-      };
-
-      ko.components.register('sql-context-contents-global-search', {
-        viewModel: SqlContextContentsGlobalSearch,
-        template: { element: 'sql-context-contents' }
-      })
-    })();
-  </script>
-
-  <script type="text/html" id="sql-columns-table-template">
-    <div class="sql-context-flex">
-      <div class="sql-context-flex-header">
-        <div style="margin: 10px 5px 0 10px;">
-          <span class="sql-context-header">${_('Columns')} (<span data-bind="text: filteredColumns().length"></span>)</span>
-          <a href="#" data-bind="toggle: searchVisible"><i class="snippet-icon fa fa-search inactive-action margin-left-10" data-bind="css: { 'blue': searchVisible }"></i></a>
-          <input class="input-large sql-context-inline-search" type="text" data-bind="visible: searchVisible, hasFocus: searchFocus, clearable: searchInput, valueUpdate:'afterkeydown'" placeholder="${ _('Filter columns...') }">
-        </div>
-      </div>
-      <div class="sql-context-flex-fill sql-columns-table" style="position:relative; height: 100%; overflow-y: auto;">
-        <table id="sqlColumnsTable" style="width: 100%" class="table table-condensed table-nowrap">
-          <!-- ko if: filteredColumns().length !== 0 -->
-          <thead>
-          <tr>
-            <th width="6%">&nbsp;</th>
-            <!-- ko if: typeof filteredColumns()[0].table === 'undefined' -->
-            <th width="60%">${_('Name')}</th>
-            <!-- /ko -->
-            <!-- ko if: typeof filteredColumns()[0].table !== 'undefined' -->
-            <th width="40%">${_('Name')}</th>
-            <th width="20%">${_('Table')}</th>
-            <!-- /ko -->
-            <th width="34%">${_('Type')}</th>
-            <th width="6%">&nbsp;</th>
-          </tr>
-          </thead>
-          <!-- /ko -->
-          <tbody data-bind="foreachVisible: { data: filteredColumns, minHeight: 29, container: '.sql-columns-table', pubSubDispose: 'context.popover.dispose' }">
-          <tr>
-            <!-- ko if: typeof selected === 'undefined' -->
-            <td data-bind="text: $index()+$indexOffset()+1"></td>
-            <!-- /ko -->
-            <!-- ko if: typeof selected !== 'undefined' -->
-            <td data-bind="toggle: selected" class="center" style="cursor: default;">
-              <div class="hueCheckbox fa" data-bind="multiCheck: '#sqlColumnsTable', css: {'fa-check': selected }"></div>
-            </td>
-
-            <!-- /ko -->
-            <td style="overflow: hidden;">
-              <!-- ko if: $parent.scrollToColumns -->
-              <a href="javascript:void(0)" class="column-selector" data-bind="text: name, click: function() { huePubSub.publish('context.popover.scroll.to.column', name); }" title="${ _("Show sample") }"></a>
-              <!-- /ko -->
-              <!-- ko ifnot: $parent.scrollToColumns -->
-              <span data-bind="text: name"></span>
-              <!-- /ko -->
-            </td>
-            <!-- ko if: typeof table !== 'undefined' -->
-            <td><span data-bind="text: table"></span></td>
-            <!-- /ko -->
-            <td><span data-bind="text: type, attr: { 'title': extendedType }, tooltip: { placement: 'bottom' }"></span></td>
-            <td><i class="snippet-icon fa fa-question-circle" data-bind="visible: comment, attr: { 'title': comment }, tooltip: { placement: 'bottom' }"></i></td>
-          </tr>
-          </tbody>
-        </table>
-        <div class="sql-context-empty-columns" data-bind="visible: filteredColumns().length === 0">${_('No columns found')}</div>
-      </div>
-    </div>
-  </script>
-
-  <script type="text/javascript">
-    (function () {
-
-      function SqlColumnsTable(params) {
-        var self = this;
-        var columns = params.columns;
-        self.scrollToColumns = typeof params.scrollToColumns !== 'undefined' ?  params.scrollToColumns : true;
-        self.searchInput = ko.observable('');
-        self.searchVisible = ko.observable(false);
-        self.searchFocus = ko.observable(false);
-
-        self.searchVisible.subscribe(function (newValue) {
-          if (newValue) {
-            self.searchFocus(true);
-          }
-        });
-
-        self.filteredColumns = ko.pureComputed(function () {
-          if (self.searchInput() === '') {
-            return columns;
-          }
-          var query = self.searchInput().toLowerCase();
-          return columns.filter(function (column) {
-            return column.name.toLowerCase().indexOf(query) != -1
-                || column.type.toLowerCase().indexOf(query) != -1
-                || column.comment.toLowerCase().indexOf(query) != -1
-                || (typeof column.table !== 'undefined' && column.table.toLowerCase().indexOf(query) !== -1);
-          })
-        });
-      }
-
-      ko.components.register('sql-columns-table', {
-        viewModel: SqlColumnsTable,
-        template: { element: 'sql-columns-table-template' }
-      });
-    })();
-  </script>
-</%def>

+ 1 - 1
desktop/libs/notebook/src/notebook/templates/editor_components.mako

@@ -846,7 +846,7 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
 
         <!-- ko foreach: pinnedContextTabs -->
         <div class="tab-pane" style="height: 300px; position: relative; overflow: hidden;" data-bind="attr: { 'id': tabId }, css: {'active': $parent.currentQueryTab() === tabId }">
-          <div style="display: flex; flex-direction: column; margin-top: 10px; overflow: hidden; height: 100%; position: relative;" data-bind="template: 'sql-context-contents'"></div>
+          <div style="display: flex; flex-direction: column; margin-top: 10px; overflow: hidden; height: 100%; position: relative;" data-bind="template: 'context-popover-contents'"></div>
         </div>
         <!-- /ko -->
       </div>

部分文件因为文件数量过多而无法显示