فهرست منبع

HUE-4838 [editor] Add S3 browsing to the assist panel

Enrico Berti 9 سال پیش
والد
کامیت
8cdc2aa837

+ 1 - 0
apps/beeswax/src/beeswax/templates/create_database.mako

@@ -42,6 +42,7 @@ ${layout.metastore_menubar()}
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 

+ 1 - 0
apps/beeswax/src/beeswax/templates/create_table_manually.mako

@@ -41,6 +41,7 @@ ${ layout.metastore_menubar() }
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 

+ 1 - 0
apps/beeswax/src/beeswax/templates/execute.mako

@@ -810,6 +810,7 @@ ${ commonshare() | n,unicode }
 <script src="${ static('desktop/js/apiHelper.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/sqlFunctions.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }" type="text/javascript" charset="utf-8"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/js/fileBrowser/hueFileEntry.js') }" type="text/javascript" charset="utf-8"></script>

+ 1 - 0
apps/beeswax/src/beeswax/templates/import_wizard_choose_delimiter.mako

@@ -42,6 +42,7 @@ ${ layout.metastore_menubar() }
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 

+ 1 - 0
apps/beeswax/src/beeswax/templates/import_wizard_choose_file.mako

@@ -41,6 +41,7 @@ ${ layout.metastore_menubar() }
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 

+ 1 - 0
apps/beeswax/src/beeswax/templates/import_wizard_define_columns.mako

@@ -42,6 +42,7 @@ ${ layout.metastore_menubar() }
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 

+ 1 - 0
apps/metastore/src/metastore/templates/describe_partitions.mako

@@ -40,6 +40,7 @@ ${ components.menubar() }
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 

+ 1 - 0
apps/metastore/src/metastore/templates/metastore.mako

@@ -53,6 +53,7 @@ ${ components.menubar() }
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 

+ 52 - 0
desktop/core/src/desktop/static/desktop/js/apiHelper.js

@@ -23,6 +23,7 @@ var ApiHelper = (function () {
   var DOCUMENTS_API = "/desktop/api2/doc/";
   var DOCUMENTS_SEARCH_API = "/desktop/api2/docs/";
   var HDFS_API_PREFIX = "/filebrowser/view=";
+  var S3_API_PREFIX = "/filebrowser/view=S3A://";
   var IMPALA_INVALIDATE_API = '/impala/api/invalidate';
   var CONFIG_SAVE_API = '/desktop/api/configurations/save/';
   var CONFIG_APPS_API = '/desktop/api/configurations';
@@ -277,6 +278,57 @@ var ApiHelper = (function () {
     }));
   };
 
+  /**
+   * @param {Object} options
+   * @param {Function} options.successCallback
+   * @param {Function} [options.errorCallback]
+   * @param {boolean} [options.silenceErrors]
+   * @param {Number} [options.timeout]
+   * @param {Object} [options.editor] - Ace editor
+   *
+   * @param {string[]} options.pathParts
+   * @param {number} [options.pageSize] - Default 500
+   * @param {number} [options.page] - Default 1
+   */
+  ApiHelper.prototype.fetchS3Path = function (options) {
+    var self = this;
+    options.pathParts.shift(); // remove the trailing /
+    var url = S3_API_PREFIX + options.pathParts.join("/") + '?format=json&sortby=name&descending=false&pagesize=' + (options.pageSize || 500) + '&pagenum=' + (options.page || 1);
+    var fetchFunction = function (storeInCache) {
+      if (options.timeout === 0) {
+        self.assistErrorCallback(options)({ status: -1 });
+        return;
+      }
+      $.ajax({
+        dataType: "json",
+        url: url,
+        timeout: options.timeout,
+        success: function (data) {
+          if (!data.error && !self.successResponseIsError(data) && typeof data.files !== 'undefined' && data.files !== null) {
+            if (data.files.length > 2) {
+              storeInCache(data);
+            }
+            options.successCallback(data);
+          } else {
+            self.assistErrorCallback(options)(data);
+          }
+        }
+      })
+      .fail(self.assistErrorCallback(options))
+      .always(function () {
+        if (typeof options.editor !== 'undefined' && options.editor !== null) {
+          options.editor.hideSpinner();
+        }
+      });
+    };
+
+    fetchCached.bind(self)($.extend({}, options, {
+      sourceType: 's3',
+      url: url,
+      fetchFunction: fetchFunction
+    }));
+  };
+
   ApiHelper.prototype.getFetchQueue = function (fetchFunction, identifier) {
     var self = this;
     if (! self.fetchQueue[fetchFunction]) {

+ 202 - 0
desktop/core/src/desktop/static/desktop/js/assist/assistS3Entry.js

@@ -0,0 +1,202 @@
+// 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.
+
+var AssistS3Entry = (function () {
+
+  var PAGE_SIZE = 50;
+
+  /**
+   * @param {object} options
+   * @param {object} options.definition
+   * @param {string} options.definition.name
+   * @param {string} options.definition.type (file, dir)
+   * @param {AssistS3Entry} options.parent
+   * @param {ApiHelper} options.apiHelper
+   * @constructor
+   */
+  function AssistS3Entry (options) {
+    var self = this;
+
+    self.definition = options.definition;
+    self.apiHelper = options.apiHelper;
+    self.parent = options.parent;
+    self.path = '';
+    if (self.parent !== null) {
+      self.path = self.parent.path;
+      if (self.parent.path !== '/') {
+        self.path += '/'
+      }
+    }
+    self.path += self.definition.name;
+    self.currentPage = 1;
+    self.hasMorePages = true;
+
+    self.entries = ko.observableArray([]);
+
+    self.loaded = false;
+    self.loading = ko.observable(false);
+    self.loadingMore = ko.observable(false);
+    self.hasErrors = ko.observable(false);
+    self.open = ko.observable(false);
+
+    self.open.subscribe(function(newValue) {
+      if (newValue && self.entries().length == 0) {
+        self.loadEntries();
+      }
+    });
+
+    self.hasEntries = ko.computed(function() {
+      return self.entries().length > 0;
+    });
+  }
+
+  AssistS3Entry.prototype.dblClick = function () {
+    var self = this;
+    huePubSub.publish('assist.dblClickS3Item', self);
+  };
+
+  AssistS3Entry.prototype.loadEntries = function(callback) {
+    var self = this;
+    if (self.loading()) {
+      return;
+    }
+    self.loading(true);
+    self.hasErrors(false);
+
+    var successCallback = function(data) {
+      self.hasMorePages = data.page.next_page_number > self.currentPage;
+      var filteredFiles = $.grep(data.files, function (file) {
+        return file.name !== '.' && file.name !== '..';
+      });
+      self.entries($.map(filteredFiles, function (file) {
+        return new AssistS3Entry({
+          definition: file,
+          parent: self,
+          apiHelper: self.apiHelper
+        })
+      }));
+      self.loaded = true;
+      self.loading(false);
+      if (callback) {
+        callback();
+      }
+    };
+
+    var errorCallback = function () {
+      self.hasErrors(true);
+      self.loading(false);
+      if (callback) {
+        callback();
+      }
+    };
+
+    self.apiHelper.fetchS3Path({
+      pageSize: PAGE_SIZE,
+      page: self.currentPage,
+      pathParts: self.getHierarchy(),
+      successCallback: successCallback,
+      errorCallback: errorCallback
+    })
+  };
+
+  AssistS3Entry.prototype.loadDeep = function(folders, callback) {
+    var self = this;
+
+    if (folders.length === 0) {
+      callback(self);
+      return;
+    }
+
+    var findNextAndLoadDeep = function () {
+      var nextName = folders.shift();
+      var foundEntry = $.grep(self.entries(), function (entry) {
+        return entry.definition.name === nextName && entry.definition.type === 'dir';
+      });
+      if (foundEntry.length === 1) {
+        foundEntry[0].loadDeep(folders, callback);
+      } else if (! self.hasErrors()) {
+        callback(self);
+      }
+    };
+
+    if (! self.loaded) {
+      self.loadEntries(findNextAndLoadDeep);
+    } else {
+      findNextAndLoadDeep();
+    }
+  };
+
+  AssistS3Entry.prototype.getHierarchy = function () {
+    var self = this;
+    var parts = [];
+    var entry = self;
+    while (entry != null) {
+      parts.push(entry.definition.name);
+      entry = entry.parent;
+    }
+    parts.reverse();
+    return parts;
+  };
+
+  AssistS3Entry.prototype.toggleOpen = function () {
+    var self = this;
+    if (self.definition.type === 'file') {
+      return;
+    }
+    self.open(!self.open());
+    if (self.definition.name === '..') {
+      if (self.parent.parent) {
+        huePubSub.publish('assist.selectS3Entry', self.parent.parent);
+      }
+    } else {
+      huePubSub.publish('assist.selectS3Entry', self);
+    }
+  };
+
+  AssistS3Entry.prototype.fetchMore = function () {
+    var self = this;
+    if (!self.hasMorePages || self.loadingMore()) {
+      return;
+    }
+    self.currentPage++;
+    self.loadingMore(true);
+    self.hasErrors(false);
+    self.apiHelper.fetchS3Path({
+      pageSize: PAGE_SIZE,
+      page: self.currentPage,
+      pathParts: self.getHierarchy(),
+      successCallback: function (data) {
+        self.hasMorePages = data.page.next_page_number > self.currentPage;
+        var filteredFiles = $.grep(data.files, function (file) {
+          return file.name !== '.' && file.name !== '..';
+        });
+        self.entries(self.entries().concat($.map(filteredFiles, function (file) {
+          return new AssistS3Entry({
+            definition: file,
+            parent: self,
+            apiHelper: self.apiHelper
+          })
+        })));
+        self.loadingMore(false);
+      },
+      errorCallback: function () {
+        self.hasErrors(true);
+      }
+    });
+  };
+
+  return AssistS3Entry;
+})();

+ 9 - 0
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -3280,6 +3280,12 @@
         }
       });
 
+      huePubSub.subscribe("assist.dblClickS3Item", function(assistS3Entry) {
+        if ($el.data("last-active-editor")) {
+          editor.session.insert(editor.getCursorPosition(), "'S3A://" + assistS3Entry.path + "'");
+        }
+      });
+
       var $tableDropMenu = $el.next('.table-drop-menu');
       var $identifierDropMenu = $tableDropMenu.find('.editor-drop-identifier');
 
@@ -3348,6 +3354,9 @@
         drop: function (e, ui) {
           var position = editor.renderer.screenToTextCoordinates(e.clientX, e.clientY);
           var text = ui.helper.text();
+          if (draggableMeta.type === 's3' || draggableMeta.type === 'hdfs'){
+            text = "'" + draggableMeta.definition.path + "'";
+          }
           editor.moveCursorToPosition(position);
           var before = editor.getTextBeforeCursor();
           if (draggableMeta.table && ! draggableMeta.column && /.*;|^\s*$/.test(before)) {

+ 138 - 1
desktop/core/src/desktop/templates/assist.mako

@@ -24,7 +24,7 @@ from metadata.conf import has_navigator
 %>
 
 
-<%def name="assistPanel()">
+<%def name="assistPanel(is_s3_enabled=False)">
   <%namespace name="sqlContextPopover" file="/sql_context_popover.mako" />
   <%namespace name="nav_components" file="/nav_components.mako" />
 
@@ -531,6 +531,86 @@ from metadata.conf import has_navigator
     </div>
   </script>
 
+  <script type="text/html" id="s3-details-content">
+    <!-- ko with: definition -->
+    <div class="assist-details-wrap">
+      <div><div class="assist-details-header">${ _('Size') }</div><div class="assist-details-value" data-bind="text: humansize"></div></div>
+      <div><div class="assist-details-header">${ _('Permissions') }</div><div class="assist-details-value" data-bind="text: rwx"></div></div>
+    </div>
+    <!-- /ko -->
+  </script>
+
+  <script type="text/html" id="s3-details-title">
+    <span data-bind="text: definition.name"></span>
+  </script>
+
+  <script type="text/html" id="assist-s3-header-actions">
+    <div class="assist-db-header-actions"style="margin-top: -1px;">
+      <a class="inactive-action" href="javascript:void(0)" data-bind="click: function () { huePubSub.publish('assist.s3.refresh'); }"><i class="pointer fa fa-refresh" data-bind="css: { 'fa-spin blue' : loading }" title="${_('Manual refresh')}"></i></a>
+    </div>
+  </script>
+
+  <script type="text/html" id="assist-s3-inner-panel">
+    <div class="assist-inner-panel">
+      <div class="assist-flex-panel">
+        <!-- ko with: selectedS3Entry -->
+        <div class="assist-flex-header assist-breadcrumb" >
+          <!-- ko if: parent !== null -->
+          <a href="javascript: void(0);" data-bind="click: function () { huePubSub.publish('assist.selectS3Entry', parent); }">
+            <i class="fa fa-chevron-left" style="font-size: 15px;margin-right:8px;"></i>
+            <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px; vertical-align: top; margin-right:4px;"></i>
+            <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: path"></span>
+          </a>
+          <!-- /ko -->
+          <!-- ko if: parent === null -->
+          <div>
+            <i class="fa fa-folder-o" style="font-size: 14px; line-height: 16px;vertical-align: top; margin-right:4px;"></i>
+            <span style="font-size: 14px;line-height: 16px;vertical-align: top;" data-bind="text: path"></span>
+          </div>
+          <!-- /ko -->
+          <!-- ko template: 'assist-s3-header-actions' --><!-- /ko -->
+        </div>
+        <div class="assist-flex-fill assist-s3-scrollable">
+          <div data-bind="visible: ! loading() && ! hasErrors()" style="position: relative;">
+            <!-- ko hueSpinner: { spin: loadingMore, overlay: true } --><!-- /ko -->
+            <ul class="assist-tables" data-bind="foreachVisible: { data: entries, minHeight: 20, container: '.assist-s3-scrollable', fetchMore: $data.fetchMore.bind($data) }">
+              <li class="assist-entry assist-table-link" style="position: relative;" data-bind="visibleOnHover: { 'selector': '.assist-actions' }">
+                <div class="assist-actions table-actions" style="opacity: 0;" >
+                  <a style="padding: 0 3px;" class="inactive-action" href="javascript:void(0);" data-bind="templatePopover : { contentTemplate: 's3-details-content', titleTemplate: 's3-details-title', minWidth: '320px' }">
+                    <i class='fa fa-info' title="${ _('Details') }"></i>
+                  </a>
+                </div>
+
+                <a href="javascript:void(0)" class="assist-entry assist-table-link" data-bind="multiClick: { click: toggleOpen, dblClick: dblClick }, attr: {'title': definition.name }">
+                  <!-- ko if: definition.type === 'dir' -->
+                  <i class="fa fa-fw fa-folder-o muted valign-middle"></i>
+                  <!-- /ko -->
+                  <!-- ko if: definition.type === 'file' -->
+                  <i class="fa fa-fw fa-file-o muted valign-middle"></i>
+                  <!-- /ko -->
+                  <span draggable="true" data-bind="text: definition.name, draggableText: { text: '\'' + path + '\'', meta: {'type': 's3', 'definition': definition} }"></span>
+                </a>
+              </li>
+            </ul>
+            <!-- ko if: !loading() && entries().length === 0 -->
+            <ul class="assist-tables">
+              <li class="assist-entry" style="font-style: italic;">${_('Empty directory')}</li>
+            </ul>
+            <!-- /ko -->
+          </div>
+          <!-- ko hueSpinner: { spin: loading, center: true, size: 'large' } --><!-- /ko -->
+          <div class="assist-errors" data-bind="visible: ! loading() && hasErrors()">
+            <span>${ _('Error loading contents.') }</span>
+          </div>
+        </div>
+        <!-- /ko -->
+      </div>
+      <!-- ko with: $parents[1] -->
+      <!-- ko template: { if: (searchInput() !== '' || searchHasFocus()) && navigatorEnabled(), name: 'nav-search-result' } --><!-- /ko -->
+      <!-- /ko -->
+    </div>
+  </script>
+
   <script type="text/html" id="hdfs-details-content">
     <!-- ko with: definition -->
     <div class="assist-details-wrap">
@@ -1260,6 +1340,50 @@ from metadata.conf import has_navigator
         });
       }
 
+
+      /**
+       * @param {Object} options
+       * @param {ApiHelper} options.apiHelper
+       * @constructor
+       **/
+      function AssistS3Panel (options) {
+        var self = this;
+        self.apiHelper = options.apiHelper;
+
+        self.selectedS3Entry = ko.observable();
+        var reload = function () {
+          var lastKnownPath = self.apiHelper.getFromTotalStorage('assist', 'currentS3Path', '/');
+          var parts = lastKnownPath.split('/');
+          parts.shift();
+
+          var currentEntry = new AssistS3Entry({
+            definition: {
+              name: '/',
+              type: 'dir'
+            },
+            parent: null,
+            apiHelper: self.apiHelper
+          });
+
+          currentEntry.loadDeep(parts, function (entry) {
+            self.selectedS3Entry(entry);
+            entry.open(true);
+          });
+        };
+
+        reload();
+
+        huePubSub.subscribe('assist.selectS3Entry', function (entry) {
+          self.selectedS3Entry(entry);
+          self.apiHelper.setInTotalStorage('assist', 'currentS3Path', entry.path);
+        });
+
+        huePubSub.subscribe('assist.s3.refresh', function () {
+          huePubSub.publish('assist.clear.s3.cache');
+          reload();
+        });
+      }
+
       /**
        * @param {Object} params
        * @param {string} params.user
@@ -1338,6 +1462,19 @@ from metadata.conf import has_navigator
           minHeight: 50
         }));
 
+        if (window.IS_S3_ENABLED) { // coming from common_header.mako
+          self.availablePanels.push(new AssistInnerPanel({
+            panelData: new AssistS3Panel({
+              apiHelper: self.apiHelper
+            }),
+            apiHelper: self.apiHelper,
+            name: '${ _("S3") }',
+            type: 's3',
+            icon: 'fa-cubes',
+            minHeight: 50
+          }));
+        }
+
         self.availablePanels.push(new AssistInnerPanel({
           panelData: new AssistDocumentsPanel({
             user: params.user,

+ 3 - 2
desktop/core/src/desktop/templates/common_header.mako

@@ -108,6 +108,7 @@ if USE_NEW_EDITOR.get():
   <script type="text/javascript" charset="utf-8">
 
     var LOGGED_USERNAME = '${ user.username }';
+    var IS_S3_ENABLED = '${ is_s3_enabled }' === 'True';
 
     // jHue plugins global configuration
     jHueFileChooserGlobals = {
@@ -453,7 +454,7 @@ if USE_NEW_EDITOR.get():
               <i class="fa fa-fw fa-file" style="vertical-align: middle"></i>${_('HDFS Browser')}</a>
             </li>
             <li><a href="/${apps['filebrowser'].display_name}/view=S3A://">
-              <i class="fa fa-fw fa-cloud" style="vertical-align: middle"></i>${_('S3 Browser')}</a>
+              <i class="fa fa-fw fa-cubes" style="vertical-align: middle"></i>${_('S3 Browser')}</a>
             </li>
           </ul>
         </li>
@@ -466,7 +467,7 @@ if USE_NEW_EDITOR.get():
       <li class="hideMoreThan1380">
         % if is_s3_enabled:
           <a title="${_('S3 Browser')}" rel="navigator-tooltip" href="/${apps['filebrowser'].display_name}/view=S3A://">
-            <i class="fa fa-cloud"></i>
+            <i class="fa fa-cubes"></i>
           </a>
         % endif
       </li>

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

@@ -38,6 +38,7 @@ ${ commonheader(_('Welcome Home'), "home", user) | n,unicode }
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 <script src="${ static('desktop/js/home2.vm.js') }"></script>

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

@@ -42,6 +42,7 @@ ${ commonheader(_("Solr Indexes"), "search", user, "60px") | n,unicode }
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>
 <script src="${ static('notebook/js/notebook.ko.js') }"></script>

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

@@ -72,6 +72,7 @@ from notebook.conf import ENABLE_QUERY_BUILDER, ENABLE_QUERY_SCHEDULING, ENABLE_
 <script src="${ static('desktop/js/assist/assistDbEntry.js') }"></script>
 <script src="${ static('desktop/js/assist/assistDbSource.js') }"></script>
 <script src="${ static('desktop/js/assist/assistHdfsEntry.js') }"></script>
+<script src="${ static('desktop/js/assist/assistS3Entry.js') }"></script>
 <script src="${ static('desktop/js/document/hueDocument.js') }"></script>
 <script src="${ static('desktop/js/document/hueFileEntry.js') }"></script>