Răsfoiți Sursa

HUE-8687 [frontend] Migrate additional jquery plugins to webpack

Johan Ahlen 6 ani în urmă
părinte
comite
282d0c31ee
44 a modificat fișierele cu 4618 adăugiri și 1948 ștergeri
  1. 1 1
      .eslintrc.js
  2. 0 0
      desktop/core/src/desktop/js/ext/jquery.dataTables.1.8.2.min.js
  3. 0 0
      desktop/core/src/desktop/js/ext/jquery.total-storage.1.1.3.min.js
  4. 0 677
      desktop/core/src/desktop/js/ext/jquery/hue.jquery.filechooser.js
  5. 0 337
      desktop/core/src/desktop/js/ext/jquery/hue.jquery.hdfs.autocomplete.js
  6. 0 121
      desktop/core/src/desktop/js/ext/jquery/hue.jquery.horizontalscrollbar.js
  7. 0 42
      desktop/core/src/desktop/js/ext/jquery/hue.jquery.lib.js
  8. 0 136
      desktop/core/src/desktop/js/ext/jquery/hue.jquery.notify.js
  9. 0 174
      desktop/core/src/desktop/js/ext/jquery/hue.jquery.selector.js
  10. 3 1
      desktop/core/src/desktop/js/hue.js
  11. 49 0
      desktop/core/src/desktop/js/jquery/jquery.all.js
  12. 28 24
      desktop/core/src/desktop/js/jquery/jquery.migration.js
  13. 7 9
      desktop/core/src/desktop/js/jquery/plugins/jquery.datatables.sorting.js
  14. 26 26
      desktop/core/src/desktop/js/jquery/plugins/jquery.delayedinput.js
  15. 849 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.filechooser.js
  16. 406 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.hdfs.autocomplete.js
  17. 741 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.hiveautocomplete.js
  18. 224 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.horizontalscrollbar.js
  19. 160 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.notify.js
  20. 36 28
      desktop/core/src/desktop/js/jquery/plugins/jquery.rowselector.js
  21. 184 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.scrollleft.js
  22. 186 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.scrollup.js
  23. 220 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.selector.js
  24. 724 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.tableextender.js
  25. 584 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.tableextender2.js
  26. 153 0
      desktop/core/src/desktop/js/jquery/plugins/jquery.tablescroller.js
  27. 21 20
      desktop/core/src/desktop/js/jquery/plugins/jquery.titleupdater.js
  28. 1 0
      desktop/core/src/desktop/js/ko/bindings/ko.dropzone.js
  29. 1 2
      desktop/core/src/desktop/js/ko/bindings/ko.medium.js
  30. 0 0
      desktop/core/src/desktop/static/desktop/ext/js/dropzone.min.js
  31. 0 0
      desktop/core/src/desktop/static/desktop/ext/js/medium-editor.min.js
  32. 0 0
      desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-c56027ed5fcc7f4abc0b.js
  33. 0 0
      desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-c56027ed5fcc7f4abc0b.js.map
  34. 0 0
      desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-cd1cd1feafc6ddb99531.js.map
  35. 1 1
      desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js
  36. 0 0
      desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js.map
  37. 0 337
      desktop/core/src/desktop/static/desktop/js/jquery.hdfsautocomplete.js
  38. 0 1
      desktop/core/src/desktop/templates/common_header.mako
  39. 0 7
      desktop/core/src/desktop/templates/hue.mako
  40. 0 2
      desktop/libs/indexer/src/indexer/templates/importer.mako
  41. 0 1
      desktop/libs/notebook/src/notebook/templates/editor_components.mako
  42. 10 0
      package-lock.json
  43. 2 0
      package.json
  44. 1 1
      webpack-stats.json

+ 1 - 1
.eslintrc.js

@@ -11,7 +11,7 @@ const hueGlobals = [
   'LOGGED_USERGROUPS', 'METASTORE_PARTITION_LIMIT', 'WorkerGlobalScope',
 
   // other misc, TODO
-  'ace', 'CodeMirror', 'Dropzone', 'impalaDagre', 'less', 'MediumEditor', 'moment', 'Plotly', 'Role', 'sqlStatementsParser', 'trackOnGA'
+  'ace', 'CodeMirror', 'impalaDagre', 'less', 'MediumEditor', 'moment', 'Plotly', 'Role', 'sqlStatementsParser', 'trackOnGA'
 ];
 
 const globals = normalGlobals.concat(hueGlobals).reduce((acc, key) => {

+ 0 - 0
desktop/core/src/desktop/js/ext/jquery/jquery.dataTables.1.8.2.min.js → desktop/core/src/desktop/js/ext/jquery.dataTables.1.8.2.min.js


+ 0 - 0
desktop/core/src/desktop/js/ext/jquery/jquery.total-storage.1.1.3.min.js → desktop/core/src/desktop/js/ext/jquery.total-storage.1.1.3.min.js


+ 0 - 677
desktop/core/src/desktop/js/ext/jquery/hue.jquery.filechooser.js

@@ -1,677 +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.
-/*
- * jHue fileChooser plugin
- */
-
-import $ from 'jquery';
-import huePubSub from '../../utils/huePubSub';
-
-var pluginName = "jHueFileChooser",
-  defaults = {
-    initialPath: "",
-    forceRefresh: false,
-    errorRedirectPath: "",
-    createFolder: true,
-    uploadFile: true,
-    selectFolder: false,
-    suppressErrors: false,
-    displayOnlyFolders: false,
-    showExtraHome: false,
-    extraHomeProperties: {},
-    filterExtensions: "",
-    labels: {
-      BACK: "Back",
-      SELECT_FOLDER: "Select this folder",
-      CREATE_FOLDER: "Create folder",
-      FOLDER_NAME: "Folder name",
-      CANCEL: "Cancel",
-      FILE_NOT_FOUND: "The file has not been found",
-      UPLOAD_FILE: "Upload a file",
-      FAILED: "Failed",
-      HOME: "Home"
-    },
-    filesystems: ['hdfs'],
-    filesysteminfo: {
-      "": {
-        scheme: "",
-        root: "/",
-        home: "/?default_to_home",
-        icon: {
-          brand: "fa-files-o",
-          home: "fa-home",
-        },
-        label : {
-          home: "home",
-          name: "HDFS",
-        }
-      },
-      hdfs: {
-        scheme: "",
-        root: "/",
-        home: "/?default_to_home",
-        icon: {
-          brand: "fa-files-o",
-          home: "fa-home",
-        },
-        label : {
-          home: "home",
-          name: "HDFS",
-        }
-      },
-      s3a: {
-        scheme: "s3a",
-        root: "s3a://",
-        home: "s3a://",
-        icon: {
-          brand: "fa-cubes",
-          home: "fa-cubes",
-        },
-        label : {
-          home: "",
-          name: "S3"
-        }
-      },
-      adl: {
-        scheme: "adl",
-        root: "adl:/",
-        home: "adl:/",
-        icon: {
-          svg:{
-            brand: "#hi-adls",
-            home: "#hi-adls"
-          },
-          brand: "fa-windows",
-          home: "fa-windows"
-        },
-        label : {
-          home: "",
-          name: "ADLS"
-        }
-      }
-    },
-    fsSelected: 'hdfs',
-    user: "",
-    onNavigate: function () {
-    },
-    onFileChoose: function () {
-    },
-    onFolderChoose: function () {
-    },
-    onFolderChange: function () {
-    },
-    onError: function () {
-    }
-  },
-  STORAGE_PREFIX = "hueFileBrowserLastPathForUser_";
-
-function Plugin(element, options) {
-  this.element = element;
-  $(element).data('jHueFileChooser', this);
-
-  this.options = $.extend({}, defaults, { user: LOGGED_USERNAME }, options);
-  this.options.labels = $.extend({}, defaults.labels, HUE_I18n.jHueFileChooser, options ? options.labels : {});
-  this._defaults = defaults;
-  this._name = pluginName;
-  this.previousPath = "";
-  this.init();
-}
-
-Plugin.prototype.setOptions = function (options) {
-  var self = this;
-  self.options = $.extend({}, defaults, { user: LOGGED_USERNAME }, options);
-  self.options.labels = $.extend({}, defaults.labels, HUE_I18n.jHueFileChooser, options ? options.labels : {});
-  var initialPath = $.trim(self.options.initialPath);
-  var scheme = initialPath && initialPath.substring(0,initialPath.indexOf(":"));
-  if (scheme && scheme.length) {
-    self.options.fsSelected = scheme;
-  }
-
-  $(self.element).find('.filechooser-services li').removeClass('active');
-  $(self.element).find('.filechooser-services li[data-fs="' + self.options.fsSelected + '"]').addClass('active');
-
-  if (self.options.forceRefresh) {
-    if (initialPath != "") {
-      self.navigateTo(self.options.initialPath);
-    } else if ($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected) != null) {
-      self.navigateTo($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected));
-    } else {
-      self.navigateTo("/?default_to_home");
-    }
-  } else {
-    if (initialPath != "") {
-      self.navigateTo(self.options.initialPath);
-    } else if ($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected) != null) {
-      self.navigateTo($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected));
-    }
-  }
-};
-
-function getScheme (path) {
-  var index = path.indexOf("://");
-  return index >= 0 ? path.substring(0, index) : "hdfs";
-}
-
-function getFs (scheme) {
-  if (scheme === 'adl') {
-    return 'adls';
-  } else if (scheme === 's3a' ){
-    return 's3';
-  } else if (!scheme || scheme === 'hdfs') {
-    return 'hdfs';
-  } else {
-    return scheme;
-  }
-}
-
-Plugin.prototype.setFileSystems = function (filesystems) {
-  var self = this, filters, filesystemsFiltered;
-  self.options.filesystems = [];
-  Object.keys(filesystems).forEach(function (k) {
-    if (filesystems[k]) {
-      self.options.filesystems.push(k);
-    }
-  });
-  self.options.filesystems.sort();
-  if (self.options.filesystemsFilter) {
-    filters = self.options.filesystemsFilter.reduce(function(filters, fs) {
-    filters[fs] = true;
-    return filters;
-  }, {});
-    filesystemsFiltered = self.options.filesystems.filter(function(fs) {
-      return filters[fs];
-    });
-  } else {
-    filesystemsFiltered = self.options.filesystems;
-  }
-
-  $(self.element).data('fs', filesystemsFiltered);
-  if (filesystemsFiltered.length > 1) {
-    var $ul = $('<ul>').addClass('nav nav-list').css('border', 'none');
-    filesystemsFiltered.forEach(function (fs) {
-      var filesysteminfo = self.options.filesysteminfo;
-      var $li = $('<li>').attr('data-fs', fs).addClass(self.options.fsSelected === fs ? 'active' : '').html('<a class="pointer" style="padding-left: 6px">' + (filesysteminfo[fs] ? filesysteminfo[fs].label.name : fs.toUpperCase()) + '</a>');
-      $li.on('click', function () {
-        $(this).siblings().removeClass('active');
-        $(this).addClass('active');
-        self.options.fsSelected = fs;
-        var storedPath = $.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected);
-        if (storedPath !== null) {
-          if (filesysteminfo[fs] && storedPath.toLowerCase().indexOf(fs) === -1) {
-            self.navigateTo(filesysteminfo[fs].home);
-          } else {
-            self.navigateTo(storedPath);
-          }
-        } else {
-          self.navigateTo(filesysteminfo[fs] ? filesysteminfo[fs].home : '/?default_to_home');
-        }
-      });
-      $li.appendTo($ul);
-    });
-    $(self.element).find('.filechooser-services').empty().width(80);
-    $(self.element).find('.filechooser-tree').width(480).css('paddingLeft', '6px').css('borderLeft', '1px solid #EEE').css('marginLeft', '80px').css('min-height', '330px');
-    $ul.appendTo($(self.element).find('.filechooser-services'));
-  }
-};
-
-//TODO: refactor this method to template
-Plugin.prototype.navigateTo = function (path) {
-  var _parent = this;
-  $(_parent.element).find('.filechooser-tree').html("<i style=\"font-size: 24px; color: #DDD\" class=\"fa fa-spinner fa-spin\"></i>");
-  var pageSize = '?pagesize=1000';
-  if (path.indexOf('?') > -1) {
-    pageSize = pageSize.replace(/\?/, '&');
-  }
-  $.getJSON("/filebrowser/view=" + path + pageSize, function (data) {
-    $(_parent.element).find('.filechooser-tree').empty();
-
-    path = data.current_dir_path || path; // use real path.
-    var _flist = $("<ul>").addClass("unstyled").css({
-      'height': '260px',
-      'overflow-y': 'auto'
-    });
-    var $homeBreadcrumb = $("<ul>").addClass("hue-breadcrumbs").css({
-      'padding': '0',
-      'marginLeft': '0',
-      'float': 'left',
-      'white-space': 'nowrap'
-    });
-    var _home = $("<li>");
-    //var filesysteminfo = self.options.filesysteminfo;
-    var fs = _parent.options.filesysteminfo[_parent.options.fsSelected || "hdfs"];
-    var el = fs.icon.svg ? '<svg class="hi"><use xlink:href="'+fs.icon.svg.home+'"></use></svg>' : '<i class="fa '+fs.icon.home+'"></i> ' + fs.label.home;
-    var _homelink = $("<a>").addClass("nounderline").html(el).css("cursor", "pointer").click(function () {
-      _parent.navigateTo(fs.home);
-    });
-
-    _homelink.appendTo(_home);
-    _home.appendTo($homeBreadcrumb);
-
-    $("<span>").addClass("divider").css("margin-right", "20px").appendTo(_home);
-
-    if (data.error || (data.title != null && data.title == "Error")) {
-      $homeBreadcrumb.appendTo($(_parent.element).find('.filechooser-tree'));
-      $("<div class='clearfix'>").appendTo($(_parent.element).find('.filechooser-tree'));
-      var _errorMsg = $("<div>").addClass("alert").addClass("alert-error").text(data.message ? data.message : data.error);
-      _errorMsg.appendTo($(_parent.element).find('.filechooser-tree'));
-      //TODO: allow user to user breadcrums when there is an error
-      var _previousLink = $("<a>").addClass("btn").text(_parent.options.labels.BACK).click(function () {
-        function getParentPath (path) {
-          if (!path) return path;
-          var indexFirst = path.indexOf("/");
-          var indexLast = path.lastIndexOf("/");
-          return indexLast - indexFirst > 1 && indexLast > 0 ? path.substring(0, indexLast + 1) : path;
-        }
-        var next = path !== _parent.previousPath && getScheme(path) === getScheme(_parent.previousPath) ? _parent.previousPath : getParentPath(path);
-        _parent.options.onFolderChange(next);
-        _parent.navigateTo(next);
-      });
-      _previousLink.appendTo($(_parent.element).find('.filechooser-tree'));
-    } else {
-      if (data.type == "file") {
-        _parent.navigateTo(data.view.dirname);
-        return;
-      }
-      $.totalStorage(STORAGE_PREFIX + _parent.options.user + _parent.options.fsSelected, path);
-      _parent.previousPath = path;
-      _parent.options.onNavigate(_parent.previousPath);
-
-      var $search = $('<div>').html('<i class="fa fa-refresh inactive-action pointer" style="position: absolute; top: 3px; margin-left: -16px"></i> <i class="fa fa-search inactive-action pointer" style="position: absolute; top: 3px"></i><input type="text" class="small-search" style="display: none; width: 0; padding: 2px; padding-left: 20px">').css({
-        'position': 'absolute',
-        'right': '20px',
-        'background-color': '#FFF'
-      });
-
-      let slideOutInput = () => {
-        $search.find('input').animate({
-          'width': '0'
-        }, 100, function(){
-          $search.find('input').hide();
-          $search.find('.fa-refresh').show();
-        });
-      }
-
-      var $searchInput = $search.find('input');
-      let tog = (v) => v ? "addClass" : "removeClass";
-      $searchInput.addClass("clearable");
-      $searchInput.on("input", function () {
-        $searchInput[tog(this.value)]("x");
-      })
-      .on("mousemove", function (e) {
-        $searchInput[tog(this.offsetWidth - 18 < e.clientX - this.getBoundingClientRect().left)]("onX");
-      })
-      .on("click", function (e) {
-        if (this.offsetWidth - 18 < e.clientX - this.getBoundingClientRect().left) {
-          $searchInput.removeClass("x onX").val("");
-        }
-      });
-      if (!isIE11) {
-        $searchInput.on("blur", function (e) {
-          if ($searchInput.val() === ''){
-            slideOutInput();
-          }
-        });
-      }
-
-      $search.find('.fa-search').on('click', function(){
-        if ($searchInput.is(':visible')){
-          slideOutInput();
-        } else {
-          $search.find('.fa-refresh').hide();
-          $searchInput.show().animate({
-            'width': '100px'
-          }, 100, function(){
-            $searchInput.focus();
-          });
-        }
-      });
-
-      $search.find('.fa-refresh').on('click', function(){
-        _parent.navigateTo(path);
-      });
-
-      $search.appendTo($(_parent.element).find('.filechooser-tree'));
-
-      var $scrollingBreadcrumbs = $("<ul>").addClass("hue-breadcrumbs editable-breadcrumbs").css({
-        'padding': '0',
-        'marginLeft': '10px',
-        'marginBottom': '0',
-        'paddingRight': '10px',
-        'float': 'left',
-        'width': '300px',
-        'overflow-x': 'scroll',
-        'overflow-y': 'hidden',
-        'white-space': 'nowrap'
-      });
-
-      if (ko && ko.bindingHandlers.delayedOverflow) {
-        ko.bindingHandlers.delayedOverflow.init($scrollingBreadcrumbs[0]);
-      }
-
-      if (_parent.options.showExtraHome) {
-        var _extraHome = $("<li>");
-        var _extraHomelink = $("<a>").addClass("nounderline").html('<i class="fa ' + _parent.options.extraHomeProperties.icon + '"></i> ' + _parent.options.extraHomeProperties.label).css("cursor", "pointer").click(function () {
-          _parent.navigateTo(_parent.options.extraHomeProperties.path);
-        });
-        _extraHomelink.appendTo(_extraHome);
-        $("<span>").addClass("divider").css("margin-right", "20px").appendTo(_extraHome);
-        _extraHome.appendTo($scrollingBreadcrumbs);
-      }
-
-      var $hdfsAutocomplete = $('<input type="text">').addClass('editable-breadcrumb-input').val(path).hide();
-
-      $scrollingBreadcrumbs.click(function (e) {
-        if ($(e.target).is('ul') || $(e.target).hasClass('spacer')) {
-          $(this).hide();
-          $hdfsAutocomplete.show().focus();
-        }
-      });
-
-      var $editBreadcrumbs = $("<li>").css('marginRight', '2px');
-      var $crumbLink = $("<span>").addClass('spacer');
-      $crumbLink.html('&nbsp;').appendTo($editBreadcrumbs);
-      $editBreadcrumbs.appendTo($scrollingBreadcrumbs);
-      if (typeof data.breadcrumbs != "undefined" && data.breadcrumbs != null) {
-        var _bLength = data.breadcrumbs.length;
-        $(data.breadcrumbs).each(function (cnt, crumb) {
-          var _crumb = $("<li>");
-          var _crumbLink = $("<a>");
-          var _crumbLabel = (crumb.label != null && crumb.label != "") ? crumb.label : "/";
-          _crumbLink.attr("href", "javascript:void(0)").text(_crumbLabel).appendTo(_crumb);
-          if (cnt < _bLength - 1) {
-            if (cnt > 0) {
-              $("<span>").addClass("divider").text("/").appendTo(_crumb);
-            } else {
-              $("<span>").html("&nbsp;").appendTo(_crumb);
-            }
-          }
-          _crumb.click(function () {
-            var _url = (crumb.url != null && crumb.url != "") ? crumb.url : "/";
-            _parent.options.onFolderChange(_url);
-            _parent.navigateTo(_url);
-          });
-          _crumb.appendTo($scrollingBreadcrumbs);
-        });
-      }
-      $homeBreadcrumb.appendTo($(_parent.element).find('.filechooser-tree'));
-      $scrollingBreadcrumbs.appendTo($(_parent.element).find('.filechooser-tree'));
-      $hdfsAutocomplete.appendTo($(_parent.element).find('.filechooser-tree'));
-
-      $hdfsAutocomplete.jHueHdfsAutocomplete({
-        home: "/user/" + _parent.options.user + "/",
-        skipEnter: true,
-        skipKeydownEvents: true,
-        onEnter: function (el) {
-          var _url = el.val();
-          _parent.options.onFolderChange(_url);
-          _parent.navigateTo(_url);
-          $("#jHueHdfsAutocomplete").hide();
-        },
-        onBlur: function () {
-          $hdfsAutocomplete.hide();
-          $scrollingBreadcrumbs.show();
-        },
-        smartTooltip: _parent.options.labels.SMART_TOOLTIP
-      });
-
-      $('<div>').addClass('clearfix').appendTo($(_parent.element).find('.filechooser-tree'));
-
-      var resizeBreadcrumbs = window.setInterval(function(){
-        if ($homeBreadcrumb.is(':visible') && $homeBreadcrumb.width() > 0){
-          window.clearInterval(resizeBreadcrumbs);
-          $scrollingBreadcrumbs.width($(_parent.element).find('.filechooser-tree').width() - $homeBreadcrumb.width() - 65);
-        }
-      }, 100);
-
-      $(data.files).each(function (cnt, file) {
-        var _addFile = file.name !== '.';
-        if (_parent.options.filterExtensions != "" && file.type == "file") {
-          var _allowedExtensions = _parent.options.filterExtensions.split(",");
-          var _fileExtension = file.name.split(".").pop().toLowerCase();
-          _addFile = _allowedExtensions.indexOf(_fileExtension) > -1;
-        }
-        if (_addFile) {
-          var _f = $("<li>");
-          var _flink = $("<a>");
-
-          if (file.type == "dir") {
-            _flink.attr("href", "javascript:void(0)");
-            if (file.path.toLowerCase().indexOf('s3a://') == 0 && (file.path.substr(6).indexOf('/') > -1 || file.path.substr(6) == '')) {
-              _flink.text(" " + (cnt > 0 ? file.name : ".."))
-            } else {
-              _flink.text(" " + (file.name != "" ? file.name : ".."));
-            }
-            if (_flink.text() !== ' ..') {
-              _f.addClass('file-list-item');
-            }
-            _flink.appendTo(_f);
-            if (file.path.toLowerCase().indexOf('s3a://') == 0 && file.path.substr(5).indexOf('/') == -1) {
-              $("<i class='fa fa-cloud'></i>").prependTo(_flink);
-            } else {
-              $("<i class='fa fa-folder'></i>").prependTo(_flink);
-            }
-            _flink.click(function () {
-              _parent.options.onFolderChange(file.path);
-              _parent.navigateTo(file.path);
-            });
-          }
-          if (file.type == "file" && !_parent.options.displayOnlyFolders) {
-            _f.addClass('file-list-item');
-            _flink.attr("href", "javascript:void(0)").text(" " + (file.name != "" ? file.name : "..")).appendTo(_f);
-            $("<i class='fa fa-file-o'></i>").prependTo(_flink);
-            _flink.click(function () {
-              _parent.options.onFileChoose(file.path);
-            });
-          }
-          _f.appendTo(_flist);
-        }
-      });
-
-      _flist.appendTo($(_parent.element).find('.filechooser-tree'));
-
-      $searchInput.jHueDelayedInput(function () {
-        var filter = $searchInput.val().toLowerCase();
-        var results = 0;
-        $(_parent.element).find('.filechooser-tree .no-results').hide();
-        $(_parent.element).find('.filechooser-tree .file-list-item').each(function(){
-          if ($(this).text().toLowerCase().indexOf(filter) > -1) {
-            $(this).show();
-            results++;
-          } else {
-            $(this).hide();
-          }
-        });
-        if (results == 0){
-          $(_parent.element).find('.filechooser-tree .no-results').show();
-        }
-      }, 300);
-
-      var _actions = $("<div>").addClass("jHueFilechooserActions");
-      var _showActions = false;
-      var _uploadFileBtn;
-      var _createFolderBtn;
-      var _selectFolderBtn;
-      if (_parent.options.uploadFile) {
-        _uploadFileBtn = $("<div>").attr("id", "file-uploader").addClass('fileChooserActionUploader');
-        _uploadFileBtn.appendTo(_actions);
-        _showActions = true;
-        initUploader(path, _parent, _uploadFileBtn, _parent.options.labels);
-      }
-      if (_parent.options.selectFolder) {
-        _selectFolderBtn = $("<a>").addClass("btn").text(_parent.options.labels.SELECT_FOLDER);
-        if (_parent.options.uploadFile) {
-          _selectFolderBtn.css("margin-top", "10px");
-        }
-        _selectFolderBtn.appendTo(_actions);
-        _showActions = true;
-        _selectFolderBtn.click(function () {
-          _parent.options.onFolderChoose(path);
-        });
-      }
-      $("<span> </span>").appendTo(_actions);
-      if (_parent.options.createFolder) {
-        _createFolderBtn = $("<a>").addClass("btn").text(_parent.options.labels.CREATE_FOLDER);
-        if (_parent.options.uploadFile) {
-          _createFolderBtn.css("margin-top", "10px");
-        }
-        _createFolderBtn.appendTo(_actions);
-        _showActions = true;
-        var _createFolderDetails = $("<form>").css({"margin-top": "10px", "position": "fixed"}).addClass("form-inline");
-        _createFolderDetails.hide();
-        var _folderName = $("<input>").attr("type", "text").attr("placeholder", _parent.options.labels.FOLDER_NAME).appendTo(_createFolderDetails);
-        $("<span> </span>").appendTo(_createFolderDetails);
-        var _folderBtn = $("<input>").attr("type", "button").attr("value", _parent.options.labels.CREATE_FOLDER).addClass("btn primary").appendTo(_createFolderDetails);
-        $("<span> </span>").appendTo(_createFolderDetails);
-        var _folderCancel = $("<input>").attr("type", "button").attr("value", _parent.options.labels.CANCEL).addClass("btn").appendTo(_createFolderDetails);
-        _folderCancel.click(function () {
-          if (_uploadFileBtn) {
-            _uploadFileBtn.removeClass("disabled");
-          }
-          _createFolderBtn.removeClass("disabled");
-          _createFolderDetails.slideUp();
-        });
-        _folderBtn.click(function () {
-          if (_folderName.val().length > 0) {
-            $.ajax({
-              type: "POST",
-              url: "/filebrowser/mkdir",
-              data: {
-                name: _folderName.val(),
-                path: path
-              },
-              success: function (xhr, status) {
-                if (status == "success") {
-                  _parent.navigateTo(path);
-                  if (_uploadFileBtn) {
-                    _uploadFileBtn.removeClass("disabled");
-                  }
-                  _createFolderBtn.removeClass("disabled");
-                  _createFolderDetails.slideUp();
-                }
-              },
-              error: function (xhr) {
-                $(document).trigger("error", xhr.responseText);
-              }
-            });
-          }
-        });
-
-        _createFolderDetails.appendTo(_actions);
-
-        _createFolderBtn.click(function () {
-          if (_uploadFileBtn) {
-            _uploadFileBtn.addClass("disabled");
-          }
-          _createFolderBtn.addClass("disabled");
-          _createFolderDetails.slideDown();
-        });
-      }
-      if (_showActions) {
-        _actions.appendTo($(_parent.element).find('.filechooser-tree'));
-      }
-
-      window.setTimeout(function () {
-        $(_parent.element).parent().scrollTop(0);
-        $scrollingBreadcrumbs.animate({
-          'scrollLeft': $scrollingBreadcrumbs.width()
-        });
-      }, 0);
-    }
-  }).fail(function (e) {
-    if (!_parent.options.suppressErrors) {
-      $(document).trigger("info", _parent.options.labels.FILE_NOT_FOUND);
-      _parent.options.onError();
-    }
-    if (e.status === 404 || e.status === 500) {
-      var fs = _parent.options.filesysteminfo[_parent.options.fsSelected || "hdfs"];
-      _parent.navigateTo(_parent.options.errorRedirectPath !== "" ? _parent.options.errorRedirectPath : fs.home);
-    } else {
-      console.error(e);
-      $(document).trigger("error", e.statusText);
-    }
-  });
-};
-
-var num_of_pending_uploads = 0;
-
-function initUploader(path, _parent, el, labels) {
-  var uploader = new qq.FileUploader({
-    element: el[0],
-    action: '/filebrowser/upload/file',
-    params: {
-      dest: path,
-      fileFieldLabel: 'hdfs_file'
-    },
-    onComplete: function (id, fileName, responseJSON) {
-      num_of_pending_uploads--;
-      if (responseJSON.status == -1) {
-        $(document).trigger("error", responseJSON.data);
-      } else if (!num_of_pending_uploads) {
-        _parent.navigateTo(path);
-        huePubSub.publish('assist.' + getFs(getScheme(path)) + '.refresh');
-      }
-    },
-    onSubmit: function (id, fileName) {
-      num_of_pending_uploads++;
-    },
-    template: '<div class="qq-uploader">' +
-    '<div class="qq-upload-drop-area"><span></span></div>' +
-    '<div class="qq-upload-button">' + labels.UPLOAD_FILE + '</div><br>' +
-    '<ul class="qq-upload-list"></ul>' +
-    '</div>',
-    fileTemplate: '<li>' +
-    '<span class="qq-upload-file"></span>' +
-    '<span class="qq-upload-spinner"></span>' +
-    '<span class="qq-upload-size"></span>' +
-    '<a class="qq-upload-cancel" href="#">' + labels.CANCEL + '</a>' +
-    '<span class="qq-upload-failed-text">' + labels.FAILED + '</span>' +
-    '</li>',
-    debug: false
-  });
-}
-
-Plugin.prototype.init = function () {
-  var self = this;
-  $(self.element).empty().html('<div class="filechooser-container" style="position: relative"><div class="filechooser-services" style="position: absolute"></div><div class="filechooser-tree" style="width: 560px"></div></div>');
-  $.post('/filebrowser/api/get_filesystems', function (data) {
-    var initialPath = $.trim(self.options.initialPath);
-    var scheme = initialPath && initialPath.substring(0,initialPath.indexOf(":"));
-    if (data && data.status === 0) {
-      if (scheme && scheme.length && data.filesystems[scheme]) {
-        self.options.fsSelected = scheme;
-      }
-      self.setFileSystems(data.filesystems);
-    }
-    if (initialPath != "") {
-      self.navigateTo(self.options.initialPath);
-    } else if ($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected) != null) {
-      self.navigateTo($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected));
-    } else {
-      self.navigateTo("/?default_to_home");
-    }
-  });
-};
-
-$.fn[pluginName] = function (options) {
-  return this.each(function () {
-    if (!$.data(this, 'plugin_' + pluginName)) {
-      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
-    }
-    else {
-      $.data(this, 'plugin_' + pluginName).setOptions(options);
-    }
-  });
-};

+ 0 - 337
desktop/core/src/desktop/js/ext/jquery/hue.jquery.hdfs.autocomplete.js

@@ -1,337 +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.
-/*
- * jHue HDFS autocomplete plugin
- * augment a textbox into an HDFS autocomplete
- */
-
-import $ from 'jquery';
-import hueUtils from '../../utils/hueUtils';
-
-var pluginName = "jHueHdfsAutocomplete",
-    defaults = {
-      home: "/",
-      onEnter: function () {
-      },
-      onBlur: function () {
-      },
-      onPathChange: function () {
-      },
-      smartTooltip: "",
-      smartTooltipThreshold: 10, // needs 10 up/down or click actions and no tab to activate the smart tooltip
-      showOnFocus: false,
-      skipKeydownEvents: false,
-      skipEnter: false,
-      skipScrollEvent: false,
-      zIndex: 33000,
-      root: "/",
-      isS3: false
-    };
-
-function Plugin(element, options) {
-  this.element = element;
-  this.options = $.extend({}, defaults, options);
-  this._defaults = defaults;
-  this._name = pluginName;
-  this.init();
-}
-
-Plugin.prototype.init = function () {
-
-  var _this = this;
-  var _el = $(_this.element);
-  _el.addClass("jHueAutocompleteElement");
-  _el.attr("autocomplete", "off"); // prevents default browser behavior
-
-  // creates autocomplete popover
-  if ($("#jHueHdfsAutocomplete").length == 0) {
-    $("<div>").attr("id", "jHueHdfsAutocomplete").addClass("jHueAutocomplete popover")
-        .attr("style", "position:absolute;display:none;max-width:1000px;z-index:" + _this.options.zIndex)
-        .html('<div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p><ul class="unstyled"></ul></p></div></div>')
-        .appendTo($(HUE_CONTAINER));
-  }
-
-  function setHueBreadcrumbCaretAtEnd(element) {
-    var elemLength = element.value.length;
-    if (document.selection) {
-      element.focus();
-      var _oSel = document.selection.createRange();
-      _oSel.moveStart('character', -elemLength);
-      _oSel.moveStart('character', elemLength);
-      _oSel.moveEnd('character', 0);
-      _oSel.select();
-    }
-    else if (element.selectionStart || element.selectionStart == '0') {
-      element.selectionStart = elemLength;
-      element.selectionEnd = elemLength;
-      element.focus();
-    }
-  }
-
-
-  _el.focus(function () {
-    $(document.body).on("contextmenu", function (e) {
-      e.preventDefault(); // prevents native menu on FF for Mac from being shown
-    });
-    setHueBreadcrumbCaretAtEnd(_this.element);
-  });
-
-  _el.keydown(function (e) {
-    if (e.keyCode == 9) {
-      e.preventDefault();
-      showHdfsAutocomplete(function () {
-        var path = _el.val();
-        if (path.indexOf("/") > -1) {
-          path = path.substr(path.lastIndexOf("/") + 1);
-        }
-        guessHdfsPath(path);
-      });
-    }
-  });
-
-  function smartTooltipMaker() {
-    if (_this.options.smartTooltip != "" && typeof $.totalStorage != "undefined" && $.totalStorage("jHueHdfsAutocompleteTooltip") != -1) {
-      var cnt = 0;
-      if ($.totalStorage("jHueHdfsAutocompleteTooltip") != null) {
-        cnt = $.totalStorage("jHueHdfsAutocompleteTooltip") + 1;
-      }
-      $.totalStorage("jHueHdfsAutocompleteTooltip", cnt);
-      if (cnt >= _this.options.smartTooltipThreshold) {
-        _el.tooltip({
-          animation: true,
-          title: _this.options.smartTooltip,
-          trigger: "manual",
-          placement: "top"
-        }).tooltip("show");
-        window.setTimeout(function () {
-          _el.tooltip("hide");
-        }, 10000);
-        $.totalStorage("jHueHdfsAutocompleteTooltip", -1);
-      }
-    }
-  }
-
-  if (! _this.options.skipScrollEvent){
-    $(window).on("scroll", function(){
-      $("#jHueHdfsAutocomplete").css("top", _el.offset().top + _el.outerHeight() - 1).css("left", _el.offset().left).width(_el.outerWidth() - 4);
-    });
-  }
-
-
-  _el.on("keydown", function (e) {
-    if (!_this.options.skipKeydownEvents && e.keyCode == 191) {
-      e.preventDefault();
-    }
-    if (e.keyCode == 32 && e.ctrlKey) {
-      e.preventDefault();
-    }
-    if (_this.options.skipEnter && e.keyCode === 13){
-      e.preventDefault();
-      e.stopPropagation();
-      e.stopImmediatePropagation();
-    }
-  });
-
-
-  var _hdfsAutocompleteSelectedIndex = -1;
-  var _filterTimeout = -1;
-  _el.keyup(function (e) {
-    window.clearTimeout(_filterTimeout);
-    if ($.inArray(e.keyCode, [38, 40, 13, 32, 191]) == -1) {
-      _hdfsAutocompleteSelectedIndex = -1;
-      _filterTimeout = window.setTimeout(function () {
-        var path = _el.val();
-        if (path.indexOf("/") > -1) {
-          path = path.substr(path.lastIndexOf("/") + 1);
-        }
-        $("#jHueHdfsAutocomplete ul li").show();
-        $("#jHueHdfsAutocomplete ul li").each(function () {
-          if ($(this).text().trim().indexOf(path) != 0) {
-            $(this).hide();
-          }
-        });
-      }, 500);
-    }
-    if (e.keyCode == 38) {
-      if (_hdfsAutocompleteSelectedIndex <= 0) {
-        _hdfsAutocompleteSelectedIndex = $("#jHueHdfsAutocomplete ul li:visible").length - 1;
-      }
-      else {
-        _hdfsAutocompleteSelectedIndex--;
-      }
-    }
-    if (e.keyCode == 40) {
-      if (_hdfsAutocompleteSelectedIndex == $("#jHueHdfsAutocomplete ul li:visible").length - 1) {
-        _hdfsAutocompleteSelectedIndex = 0;
-      }
-      else {
-        _hdfsAutocompleteSelectedIndex++;
-      }
-    }
-    if (e.keyCode == 38 || e.keyCode == 40) {
-      smartTooltipMaker();
-      $("#jHueHdfsAutocomplete ul li").removeClass("active");
-      $("#jHueHdfsAutocomplete ul li:visible").eq(_hdfsAutocompleteSelectedIndex).addClass("active");
-      $("#jHueHdfsAutocomplete .popover-content").scrollTop($("#jHueHdfsAutocomplete ul li:visible").eq(_hdfsAutocompleteSelectedIndex).prevAll().length * $("#jHueHdfsAutocomplete ul li:visible").eq(_hdfsAutocompleteSelectedIndex).outerHeight());
-    }
-    if ((e.keyCode == 32 && e.ctrlKey) || e.keyCode == 191) {
-      smartTooltipMaker();
-      showHdfsAutocomplete();
-    }
-    if (e.keyCode == 13) {
-      if (_hdfsAutocompleteSelectedIndex > -1) {
-        $("#jHueHdfsAutocomplete ul li:visible").eq(_hdfsAutocompleteSelectedIndex).click();
-      }
-      else {
-        _this.options.onEnter($(this));
-      }
-      $("#jHueHdfsAutocomplete").hide();
-      _hdfsAutocompleteSelectedIndex = -1;
-    }
-  });
-
-  if (_this.options.showOnFocus){
-    _el.on("focus", function(){
-      showHdfsAutocomplete();
-    });
-  }
-
-  var _pauseBlur = false;
-
-  _el.blur(function () {
-    if (!_pauseBlur) {
-      $(document.body).off("contextmenu");
-      $("#jHueHdfsAutocomplete").hide();
-      _this.options.onBlur();
-    }
-  });
-
-  var BASE_PATH = "/filebrowser/view=";
-  var _currentFiles = [];
-
-  function showHdfsAutocomplete(callback) {
-    var base = "";
-    var path = _el.val();
-    var hasScheme = path.indexOf(":/") >= 0;
-    var isRelative = !hasScheme && path.charAt(0) !== "/";
-    if (isRelative && _this.options.root) {
-      base += _this.options.root;
-    }
-    var autocompleteUrl = BASE_PATH + base + path;
-    $.getJSON(autocompleteUrl + "?pagesize=1000&format=json", function (data) {
-      _currentFiles = [];
-      if (data.error == null) {
-        $(data.files).each(function (cnt, item) {
-          if (item.name != ".") {
-            var ico = "fa-file-o";
-            if (item.type == "dir") {
-              ico = "fa-folder";
-            }
-            _currentFiles.push('<li class="hdfsAutocompleteItem" data-value="' + hueUtils.escapeOutput(item.name) + '"><i class="fa ' + ico + '"></i> ' + hueUtils.escapeOutput(item.name) + '</li>');
-          }
-        });
-        window.setTimeout(function () {
-          $("#jHueHdfsAutocomplete").css("top", _el.offset().top + _el.outerHeight() - 1).css("left", _el.offset().left).width(_el.outerWidth() - 4);
-          $("#jHueHdfsAutocomplete").find("ul").empty().html(_currentFiles.join(""));
-          $("#jHueHdfsAutocomplete").find("li").on("click", function (e) {
-            smartTooltipMaker();
-            e.preventDefault();
-            var item = $(this).text().trim();
-            if (item == "..") { // one folder up
-              path = path.substring(0, path.lastIndexOf("/"));
-            } else {
-              path = path + (path.charAt(path.length - 1) == "/" ? "" : "/") + item;
-            }
-            _el.val(base + path);
-            if ($(this).html().indexOf("folder") > -1) {
-              _el.val(_el.val() + "/");
-              _this.options.onPathChange(_el.val());
-              showHdfsAutocomplete();
-            }
-            else {
-              _this.options.onEnter(_el);
-            }
-          });
-          $("#jHueHdfsAutocomplete").show();
-          setHueBreadcrumbCaretAtEnd(_this.element);
-          if ("undefined" != typeof callback) {
-            callback();
-          }
-        }, 100);  // timeout for IE8
-      }
-    });
-  }
-
-  $(document).on("mouseenter", ".hdfsAutocompleteItem", function () {
-    _pauseBlur = true;
-  });
-
-  $(document).on("mouseout", ".hdfsAutocompleteItem", function () {
-    _pauseBlur = false;
-  })
-
-  function guessHdfsPath(lastChars) {
-    var possibleMatches = [];
-    for (var i = 0; i < _currentFiles.length; i++) {
-      if (($(_currentFiles[i]).text().trim().indexOf(lastChars) == 0 || lastChars == "") && $(_currentFiles[i]).text().trim() != "..") {
-        possibleMatches.push(_currentFiles[i]);
-      }
-    }
-    if (possibleMatches.length == 1) {
-      _el.val(_el.val() + $(possibleMatches[0]).text().trim().substr(lastChars.length));
-      if ($(possibleMatches[0]).html().indexOf("folder") > -1) {
-        _el.val(_el.val() + "/");
-        showHdfsAutocomplete();
-      }
-    }
-    else if (possibleMatches.length > 1) {
-      // finds the longest common prefix
-      var possibleMatchesPlain = [];
-      for (var z = 0; z < possibleMatches.length; z++) {
-        possibleMatchesPlain.push($(possibleMatches[z]).text().trim());
-      }
-      var arr = possibleMatchesPlain.slice(0).sort(),
-          word1 = arr[0], word2 = arr[arr.length - 1],
-          j = 0;
-      while (word1.charAt(j) == word2.charAt(j))++j;
-      var match = word1.substring(0, j);
-      _el.val(_el.val() + match.substr(lastChars.length));
-    }
-  }
-};
-
-Plugin.prototype.setOptions = function (options) {
-  this.options = $.extend({}, defaults, options);
-};
-
-
-$.fn[pluginName] = function (options) {
-  return this.each(function () {
-    if (!$.data(this, 'plugin_' + pluginName)) {
-      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
-    }
-    else {
-      $.data(this, 'plugin_' + pluginName).setOptions(options);
-    }
-  });
-}
-
-$[pluginName] = function (options) {
-  if (typeof console != "undefined") {
-    console.warn("$(elem).jHueHdfsAutocomplete() is a preferred call method.");
-  }
-  $(options.element).jHueHdfsAutocomplete(options);
-};

+ 0 - 121
desktop/core/src/desktop/js/ext/jquery/hue.jquery.horizontalscrollbar.js

@@ -1,121 +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.
-/*
- * jHue horizontal scrollbar for dataTables_wrapper
- *
- */
-
-var pluginName = "jHueHorizontalScrollbar",
-  defaults = {};
-
-function Plugin(element, options) {
-  this.element = element;
-  this.options = $.extend({}, defaults, options);
-  this._defaults = defaults;
-  this._name = pluginName;
-  this.init();
-}
-
-function initWhenReady(el) {
-  if ($(el).parents('.dataTables_wrapper').length > 0) {
-    var colWidth = $(el).find('thead tr th').outerWidth();
-    if ($(el).parents('.dataTables_wrapper').find('.hue-scrollbar-x-rail').length == 0 && $(el).parents('.dataTables_wrapper').width() < $(el).parents('.dataTables_wrapper')[0].scrollWidth) {
-      $('.hue-scrollbar-x-rail').remove();
-      var scrollbarRail = $('<div>');
-      var scrollbar = $('<div>').addClass('hue-scrollbar-x');
-      scrollbar.width(Math.max(20, $(el).parents('.dataTables_wrapper').width() * ($(el).parents('.dataTables_wrapper').width() / $(el).parents('.dataTables_wrapper')[0].scrollWidth)));
-      scrollbar.appendTo(scrollbarRail);
-      try {
-        scrollbar.draggable('destroy');
-      }
-      catch (e) {}
-      var throttleScrollTimeout = -1;
-      scrollbar.draggable({
-        axis: 'x',
-        containment: 'parent',
-        drag: function (e, ui) {
-          $(el).parents('.dataTables_wrapper').scrollLeft(($(el).parents('.dataTables_wrapper')[0].scrollWidth - $(el).parents('.dataTables_wrapper').width()) * (ui.position.left / (scrollbarRail.width() - $(this).width())))
-          throttleScrollTimeout = window.setTimeout(function () {
-            $(el).parents('.dataTables_wrapper').trigger('scroll');
-          }, 50);
-        }
-      });
-      $(el).parents('.dataTables_wrapper').bind('mousewheel', function (e) {
-        var _deltaX = e.deltaX*e.deltaFactor,
-            _deltaY = e.deltaY;
-
-        if (Math.abs(_deltaX) >= Math.abs(_deltaY)) {
-          var self = this;
-          self.scrollLeft += _deltaX;
-          e.preventDefault();
-          e.stopPropagation();
-          e.stopImmediatePropagation();
-          if (self.scrollLeft > 0){
-            scrollbar.css("left", ((scrollbarRail[0].getBoundingClientRect().width - scrollbar[0].getBoundingClientRect().width) * (self.scrollLeft / (self.scrollWidth - self.getBoundingClientRect().width))) + "px");
-            window.clearTimeout(throttleScrollTimeout);
-            throttleScrollTimeout = window.setTimeout(function () {
-              $(el).parents('.dataTables_wrapper').trigger('scroll');
-            }, 50);
-          }
-        }
-      });
-      scrollbarRail.addClass('hue-scrollbar-x-rail').appendTo($(el).parents(".dataTables_wrapper"));
-      scrollbarRail.width($(el).parents(".dataTables_wrapper").width() - colWidth);
-      scrollbarRail.css("marginLeft", (colWidth) + "px");
-      if (scrollbarRail.position().top > $(window).height() - 10) {
-        scrollbarRail.css('bottom', '0');
-      }
-      $(el).parents('.dataTables_wrapper').bind('scroll_update', function () {
-        scrollbar.css("left", ((scrollbarRail.width() - scrollbar.width()) * ($(el).parents('.dataTables_wrapper').scrollLeft() / ($(el).parents('.dataTables_wrapper')[0].scrollWidth - $(el).parents('.dataTables_wrapper').width()))) + "px");
-      });
-    } else {
-      if ($(el).parents('.dataTables_wrapper').width() === $(el).parents('.dataTables_wrapper')[0].scrollWidth) {
-        $('.hue-scrollbar-x-rail').hide();
-      }
-      else {
-        $('.hue-scrollbar-x-rail').show();
-      }
-      $(el).parents('.dataTables_wrapper').find('.hue-scrollbar-x-rail').width($(el).parents(".dataTables_wrapper").width() - colWidth);
-      var scrollbar = $(el).parents('.dataTables_wrapper').find('.hue-scrollbar-x');
-      scrollbar.width(Math.max(20, $(el).parents('.dataTables_wrapper').width() * ($(el).parents('.dataTables_wrapper').width() / $(el).parents('.dataTables_wrapper')[0].scrollWidth)));
-
-      var scrollbarRail = $(el).parents('.dataTables_wrapper').find('.hue-scrollbar-x-rail');
-      scrollbarRail.width($(el).parents(".dataTables_wrapper").width() - colWidth);
-      scrollbarRail.css("marginLeft", (colWidth) + "px");
-      scrollbar.css("left", ((scrollbarRail.width() - scrollbar.width()) * ($(el).parents('.dataTables_wrapper').scrollLeft() / ($(el).parents('.dataTables_wrapper')[0].scrollWidth - $(el).parents('.dataTables_wrapper').width()))) + "px");
-    }
-  }
-}
-
-Plugin.prototype.init = function () {
-  var el = this.element;
-
-  var checkWidth = function () {
-    if ($(el).parents('.dataTables_wrapper').width() > 0) {
-      initWhenReady(el);
-    } else {
-      window.setTimeout(checkWidth, 100);
-    }
-  }
-
-  checkWidth();
-};
-
-$.fn[pluginName] = function (options) {
-  return this.each(function () {
-    $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
-  });
-}

+ 0 - 42
desktop/core/src/desktop/js/ext/jquery/hue.jquery.lib.js

@@ -1,42 +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.
-
-import 'jquery'
-import './hue.jquery.migration'
-import 'jquery.cookie'
-import './jquery.dataTables.1.8.2.min'
-import './hue.jquery.datatables.sorting'
-import './hue.jquery.delayedinput'
-import './hue.jquery.filechooser'
-import 'jquery-form'
-import './hue.jquery.hdfs.autocomplete'
-import './hue.jquery.horizontalscrollbar'
-import './hue.jquery.notify'
-import './hue.jquery.rowselector'
-import './hue.jquery.selector'
-import './jquery.total-storage.1.1.3.min'
-import './hue.jquery.titleupdater'
-import 'jquery-ui/ui/widgets/autocomplete'
-import 'jquery-ui/ui/widgets/mouse'
-import 'jquery-ui/ui/widgets/draggable'
-import 'jquery-ui/ui/widgets/droppable'
-import 'jquery-ui/ui/widgets/resizable'
-import 'jquery-ui/ui/widgets/sortable'
-import 'selectize'
-// chunks
-
-// window.$ = $;
-// window.jQuery = $;

+ 0 - 136
desktop/core/src/desktop/js/ext/jquery/hue.jquery.notify.js

@@ -1,136 +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.
-/*
- * jHue notify plugin
- *
- */
-import $ from 'jquery';
-
-var pluginName = "jHueNotify",
-  TYPES = {
-    INFO: "INFO",
-    ERROR: "ERROR",
-    GENERAL: "GENERAL"
-  },
-  defaults = {
-    level: TYPES.GENERAL,
-    message: "",
-    sticky: false,
-    css: null
-  };
-
-function Plugin(options) {
-  this.options = $.extend({}, defaults, options);
-  this._defaults = defaults;
-  this._name = pluginName;
-  this.show();
-}
-
-Plugin.prototype.setOptions = function (options) {
-  this.options = $.extend({}, defaults, options);
-};
-
-Plugin.prototype.show = function () {
-  var _this = this;
-  var MARGIN = 4;
-
-  _this.options.message = _this.options.message.replace(/(<([^>]+)>)/ig, ''); // escape HTML messages
-
-  if (_this.options.message !== '' && $(".jHueNotify .message").last().text() !== _this.options.message) {
-
-    var el = $("#jHueNotify").clone();
-    el.removeAttr("id");
-
-    // stops all the current animations and resets the style
-    el.stop(true);
-    el.attr("class", "alert jHueNotify");
-    el.find(".close").hide();
-
-    if ($(".jHueNotify").last().position() != null) {
-      el.css("top", $(".jHueNotify").last().position().top + $(".jHueNotify").last().outerHeight() + MARGIN);
-    }
-
-    var scrollColor = '#f0c36d';
-
-    if (_this.options.level == TYPES.ERROR) {
-      el.addClass("alert-error");
-      scrollColor = '#b94a48';
-    }
-    else if (_this.options.level == TYPES.INFO) {
-      el.addClass("alert-info");
-      scrollColor = '#0B7FAD';
-    }
-    el.find(".message").html("<strong>" + _this.options.message + "</strong>");
-
-    if (_this.options.css != null) {
-      el.attr("style", _this.options.css);
-    }
-
-    el.on('dblclick', function () {
-      el.toggleClass('expanded');
-    });
-
-    if (_this.options.sticky) {
-      el.find(".close").click(function () {
-        el.fadeOut();
-        el.nextAll(".jHueNotify").animate({
-          top: '-=' + (el.outerHeight() + MARGIN)
-        }, 200);
-        el.remove();
-      }).show();
-      el.show();
-    }
-    else {
-      var t = window.setTimeout(function () {
-        el.fadeOut();
-        el.nextAll(".jHueNotify").animate({
-          top: '-=' + (el.outerHeight() + MARGIN)
-        }, 200);
-        el.remove();
-
-      }, 3000);
-      el.click(function () {
-        window.clearTimeout(t);
-        $(this).stop(true);
-        $(this).fadeOut();
-        $(this).nextAll(".jHueNotify").animate({
-          top: '-=' + ($(this).outerHeight() + MARGIN)
-        }, 200);
-      });
-      el.show();
-    }
-    el.appendTo(HUE_CONTAINER);
-  }
-};
-
-$[pluginName] = function () {
-};
-
-$[pluginName].info = function (message) {
-  new Plugin({level: TYPES.INFO, message: message});
-};
-
-$[pluginName].warn = function (message) {
-  new Plugin({level: TYPES.GENERAL, message: message, sticky: true});
-};
-
-$[pluginName].error = function (message) {
-  new Plugin({level: TYPES.ERROR, message: message, sticky: true});
-};
-
-$[pluginName].notify = function (options) {
-  new Plugin(options);
-};

+ 0 - 174
desktop/core/src/desktop/js/ext/jquery/hue.jquery.selector.js

@@ -1,174 +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.
-/*
- * jHue selector plugin
- * it tranforms a select multiple into a searchable/selectable alphabetical list
- */
-
-var pluginName = "jHueSelector",
-    defaults = {
-      selectAllLabel: "Select all",
-      showSelectAll: true,
-      searchPlaceholder: "Search",
-      noChoicesFound: "No choices found for this element",
-      width: 300,
-      height: 200,
-      onChange: function () {
-      }
-    };
-
-function Plugin(element, options) {
-  this.element = element;
-  this.options = $.extend({}, defaults, options);
-  this._defaults = defaults;
-  this._name = pluginName;
-  this.init();
-}
-
-Plugin.prototype.setOptions = function (options) {
-  this.options = $.extend({}, defaults, options);
-};
-
-Plugin.prototype.init = function () {
-  var _this = this;
-  var addressBook = [];
-  var selectorContainer = $("<div>");
-  if (this.options.width != 300) {
-    selectorContainer.width(this.options.width);
-  }
-  $(_this.element).hide();
-  $(_this.element).find("option").each(function (cnt, opt) {
-    var initial = $(opt).text().substr(0, 1).toLowerCase();
-    if (addressBook[initial] == null) {
-      addressBook[initial] = [];
-    }
-    addressBook[initial].push($(opt));
-  });
-  var sortedKeys = [];
-  for (var key in addressBook) {
-    if (addressBook.hasOwnProperty(key)) {
-      sortedKeys.push(key);
-    }
-  }
-  sortedKeys.sort();
-
-  if (sortedKeys.length == 0) {
-    $(_this.element).after($("<div>").addClass("alert").css("margin-top", "-2px").css("float", "left").html(this.options.noChoicesFound));
-  }
-  else {
-    selectorContainer.addClass("jHueSelector");
-    var body = $("<div>").addClass("jHueSelectorBody");
-    body.appendTo(selectorContainer);
-
-    for (var i = 0; i < sortedKeys.length; i++) {
-      var key = sortedKeys[i];
-      var ul = $("<ul>");
-      var dividerLi = $("<li>").addClass("selectorDivider");
-      dividerLi.html("<strong>" + key.toUpperCase() + "</strong>");
-      dividerLi.appendTo(ul);
-      $.each(addressBook[key], function (cnt, opt) {
-        var li = $("<li>");
-        var lbl = $("<label>").text(opt.text());
-        var chk = $("<input>").attr("type", "checkbox").addClass("selector").change(function () {
-          if ($(this).is(":checked")) {
-            $(this).data("opt").attr("selected", "selected");
-          }
-          else {
-            $(this).data("opt").removeAttr("selected");
-          }
-          _this.options.onChange();
-        }).data("opt", opt).prependTo(lbl);
-        if (opt.is(":selected")) {
-          chk.attr("checked", "checked");
-        }
-        lbl.appendTo(li);
-        li.appendTo(ul);
-      });
-      ul.appendTo(body);
-    }
-
-    var header = $("<div>").addClass("jHueSelectorHeader");
-    header.prependTo(selectorContainer);
-
-    var selectAll = $("<label>").html("&nbsp;");
-
-    if (this.options.showSelectAll) {
-      selectAll.text(this.options.selectAllLabel);
-      $("<input>").attr("type", "checkbox").change(function () {
-        var isChecked = $(this).is(":checked");
-        selectorContainer.find("input.selector:visible").each(function () {
-          if (isChecked) {
-            $(this).prop("checked", true);
-            $(this).data("opt").attr("selected", "selected");
-          }
-          else {
-            $(this).prop("checked", false);
-            $(this).data("opt").removeAttr("selected");
-          }
-        });
-        if (searchBox.val() != "") {
-          $(this).prop("checked", false);
-        }
-        _this.options.onChange();
-      }).prependTo(selectAll);
-    }
-
-    selectAll.appendTo(header);
-
-    var searchBox = $("<input>").attr("type", "text").attr("placeholder", this.options.searchPlaceholder).keyup(function () {
-      body.find("ul").attr("show", true).show();
-      var q = $.trim($(this).val());
-      if (q != "") {
-        body.find("li.selectorDivider").hide();
-        body.find("label").each(function () {
-          if ($(this).text().toLowerCase().indexOf(q.toLowerCase()) > -1) {
-            $(this).parent().show();
-          }
-          else {
-            $(this).parent().hide();
-          }
-        });
-        body.find("ul").attr("show", false);
-        body.find("ul > *:visible").parent().attr("show", true).find("li.selectorDivider").show();
-      }
-      else {
-        body.find("li.selectorDivider").show();
-        body.find("label").parent().show();
-      }
-      body.find("ul[show=false]").hide();
-      body.find("ul[show=true]").show();
-    });
-    if (this.options.width != 300) {
-      searchBox.css("margin-left", this.options.width - 120 + "px");
-    }
-    searchBox.prependTo(header);
-
-    body.height(this.options.height - header.outerHeight());
-
-    $(_this.element).after(selectorContainer);
-  }
-};
-
-$.fn[pluginName] = function (options) {
-  return this.each(function () {
-    if (!$.data(this, 'plugin_' + pluginName)) {
-      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
-    }
-    else {
-      $.data(this, 'plugin_' + pluginName).setOptions(options);
-    }
-  });
-}

+ 3 - 1
desktop/core/src/desktop/js/hue.js

@@ -14,9 +14,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import 'ext/jquery/hue.jquery.lib';
+import 'jquery/jquery.all';
 import 'ext/bootstrap.2.3.2.min';
 import _ from 'lodash';
+import Dropzone from 'dropzone';
 import filesize from 'filesize';
 import qq from 'ext/fileuploader.custom';
 import page from 'page';
@@ -56,6 +57,7 @@ window.apiHelper = apiHelper;
 window.CancellablePromise = CancellablePromise;
 window.contextCatalog = contextCatalog;
 window.dataCatalog = dataCatalog;
+window.Dropzone = Dropzone;
 window.filesize = filesize;
 window.hueUtils = hueUtils;
 window.hueAnalytics = hueAnalytics;

+ 49 - 0
desktop/core/src/desktop/js/jquery/jquery.all.js

@@ -0,0 +1,49 @@
+// 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.
+
+import 'jquery';
+import 'jquery/jquery.migration';
+
+import 'jquery.cookie';
+import 'jquery-form';
+import 'selectize';
+import 'jquery-ui/ui/widgets/autocomplete';
+import 'jquery-ui/ui/widgets/mouse';
+import 'jquery-ui/ui/widgets/draggable';
+import 'jquery-ui/ui/widgets/droppable';
+import 'jquery-ui/ui/widgets/resizable';
+import 'jquery-ui/ui/widgets/sortable';
+
+import 'ext/jquery.dataTables.1.8.2.min';
+import 'ext/jquery.total-storage.1.1.3.min';
+
+import 'jquery/plugins/jquery.datatables.sorting';
+import 'jquery/plugins/jquery.delayedinput';
+import 'jquery/plugins/jquery.filechooser';
+import 'jquery/plugins/jquery.hdfs.autocomplete';
+import 'jquery/plugins/jquery.hiveautocomplete';
+import 'jquery/plugins/jquery.horizontalscrollbar';
+import 'jquery/plugins/jquery.notify';
+import 'jquery/plugins/jquery.rowselector';
+import 'jquery/plugins/jquery.scrollleft';
+import 'jquery/plugins/jquery.selector';
+import 'jquery/plugins/jquery.tableextender';
+import 'jquery/plugins/jquery.tableextender2';
+import 'jquery/plugins/jquery.tablescroller';
+import 'jquery/plugins/jquery.titleupdater';
+
+// window.$ = $;
+// window.jQuery = $;

+ 28 - 24
desktop/core/src/desktop/js/ext/jquery/hue.jquery.migration.js → desktop/core/src/desktop/js/jquery/jquery.migration.js

@@ -20,29 +20,30 @@
 
 import jQuery from 'jquery';
 
-jQuery.uaMatch = function (ua) {
+jQuery.uaMatch = function(ua) {
   ua = ua.toLowerCase();
 
-  var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
+  const match =
+    /(chrome)[ \/]([\w.]+)/.exec(ua) ||
     /(webkit)[ \/]([\w.]+)/.exec(ua) ||
     /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
     /(msie) ([\w.]+)/.exec(ua) ||
-    ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
+    (ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua)) ||
     [];
 
   return {
-    browser: match[ 1 ] || "",
-    version: match[ 2 ] || "0"
+    browser: match[1] || '',
+    version: match[2] || '0'
   };
 };
 
 // Don't clobber any existing jQuery.browser in case it's different
 if (!jQuery.browser) {
-  let matched = jQuery.uaMatch(navigator.userAgent);
-  let browser = {};
+  const matched = jQuery.uaMatch(navigator.userAgent);
+  const browser = {};
 
   if (matched.browser) {
-    browser[ matched.browser ] = true;
+    browser[matched.browser] = true;
     browser.version = matched.version;
   }
 
@@ -58,41 +59,45 @@ if (!jQuery.browser) {
 
 // Since jQuery.clean is used internally on older versions, we only shim if it's missing
 if (!jQuery.clean) {
-  let rscriptType = /\/(java|ecma)script/i;
+  const rscriptType = /\/(java|ecma)script/i;
 
-  jQuery.clean = function (elems, context, fragment, scripts) {
+  jQuery.clean = function(elems, context, fragment, scripts) {
     // Set context per 1.8 logic
     context = context || document;
-    context = !context.nodeType && context[0] || context;
+    context = (!context.nodeType && context[0]) || context;
     context = context.ownerDocument || context;
 
-    var i, elem, handleScript, jsTags,
-      ret = [];
+    let i, elem, handleScript, jsTags;
+
+    const ret = [];
 
     jQuery.merge(ret, jQuery.buildFragment(elems, context).childNodes);
 
     // Complex logic lifted directly from jQuery 1.8
     if (fragment) {
       // Special handling of each script element
-      handleScript = function (elem) {
+      handleScript = function(elem) {
         // Check if we consider it executable
         if (!elem.type || rscriptType.test(elem.type)) {
           // Detach the script and store it in the scripts array (if provided) or the fragment
           // Return truthy to indicate that it has been handled
-          return scripts ?
-            scripts.push(elem.parentNode ? elem.parentNode.removeChild(elem) : elem) :
-            fragment.appendChild(elem);
+          return scripts
+            ? scripts.push(elem.parentNode ? elem.parentNode.removeChild(elem) : elem)
+            : fragment.appendChild(elem);
         }
       };
 
       for (i = 0; (elem = ret[i]) != null; i++) {
         // Check if we're done after handling an executable script
-        if (!( jQuery.nodeName(elem, "script") && handleScript(elem) )) {
+        if (!(jQuery.nodeName(elem, 'script') && handleScript(elem))) {
           // Append to fragment and handle embedded scripts
           fragment.appendChild(elem);
-          if (typeof elem.getElementsByTagName !== "undefined") {
+          if (typeof elem.getElementsByTagName !== 'undefined') {
             // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
-            jsTags = jQuery.grep(jQuery.merge([], elem.getElementsByTagName("script")), handleScript);
+            jsTags = jQuery.grep(
+              jQuery.merge([], elem.getElementsByTagName('script')),
+              handleScript
+            );
 
             // Splice the scripts into ret after their former ancestor and advance our index beyond them
             ret.splice.apply(ret, [i + 1, 0].concat(jsTags));
@@ -106,9 +111,8 @@ if (!jQuery.clean) {
   };
 }
 
+const oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
 
-let oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
-
-jQuery.fn.andSelf = function () {
+jQuery.fn.andSelf = function() {
   return oldSelf.apply(this, arguments);
-};
+};

+ 7 - 9
desktop/core/src/desktop/js/ext/jquery/hue.jquery.datatables.sorting.js → desktop/core/src/desktop/js/jquery/plugins/jquery.datatables.sorting.js

@@ -14,19 +14,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import $ from 'jquery'
+import $ from 'jquery';
 
-$.fn.dataTableExt.afnSortData['dom-sort-value'] = function (oSettings, iColumn) {
-  var aData = [];
-  oSettings.oApi._fnGetTrNodes(oSettings).forEach(function (nRow) {
-    var oElem = $('td:eq(' + iColumn + ')', nRow);
-    var _val = oElem.text();
+$.fn.dataTableExt.afnSortData['dom-sort-value'] = function(oSettings, iColumn) {
+  const aData = [];
+  oSettings.oApi._fnGetTrNodes(oSettings).forEach(nRow => {
+    const oElem = $('td:eq(' + iColumn + ')', nRow);
+    let _val = oElem.text();
     if (typeof oElem.attr('data-sort-value') == 'undefined') {
       if (typeof oElem.find('span').attr('data-sort-value') != 'undefined') {
         _val = parseInt(oElem.find('span').attr('data-sort-value'));
       }
-    }
-    else {
+    } else {
       _val = parseInt(oElem.attr('data-sort-value'));
     }
     aData.push(_val);
@@ -34,4 +33,3 @@ $.fn.dataTableExt.afnSortData['dom-sort-value'] = function (oSettings, iColumn)
 
   return aData;
 };
-

+ 26 - 26
desktop/core/src/desktop/js/ext/jquery/hue.jquery.delayedinput.js → desktop/core/src/desktop/js/jquery/plugins/jquery.delayedinput.js

@@ -13,20 +13,21 @@
 // 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.
-/*
-* jHue Delayed Input plugin
-* use it with
-* $("#element").jHueDelayedInput( __FUNCTION_YOU_WANT_TO_CALL__, __TIMEOUT_IN_MS__ [optional])
-*/
 
-import $ from 'jquery'
+import $ from 'jquery';
+
+/*
+ * jHue Delayed Input plugin
+ * use it with
+ * $("#element").jHueDelayedInput( __FUNCTION_YOU_WANT_TO_CALL__, __TIMEOUT_IN_MS__ [optional])
+ */
 
-var pluginName = "jHueDelayedInput",
-    defaults = {
-      fn: null,
-      timeout: 300,
-      skipOnEnterAndKeys: false
-    };
+const pluginName = 'jHueDelayedInput',
+  defaults = {
+    fn: null,
+    timeout: 300,
+    skipOnEnterAndKeys: false
+  };
 
 function Plugin(element, options) {
   this.element = element;
@@ -36,18 +37,18 @@ function Plugin(element, options) {
   this.init();
 }
 
-Plugin.prototype.setOptions = function (options) {
+Plugin.prototype.setOptions = function(options) {
   this.options = $.extend({}, defaults, options);
 };
 
-Plugin.prototype.init = function () {
-  var _this = this;
-  var _timeout = -1;
+Plugin.prototype.init = function() {
+  const _this = this;
+  let _timeout = -1;
   if (_this.options.fn != null) {
-    var event = isIE11 ? 'input' : 'keyup';
+    const event = isIE11 ? 'input' : 'keyup';
 
-    $(_this.element).on(event, function (e) {
-      if (!(_this.options.skipOnEnterAndKeys && [13, 37, 38, 39, 40].indexOf(e.keyCode) > -1)){
+    $(_this.element).on(event, e => {
+      if (!(_this.options.skipOnEnterAndKeys && [13, 37, 38, 39, 40].indexOf(e.keyCode) > -1)) {
         window.clearTimeout(_timeout);
         _timeout = window.setTimeout(_this.options.fn, _this.options.timeout);
       }
@@ -55,18 +56,17 @@ Plugin.prototype.init = function () {
   }
 };
 
-$.fn[pluginName] = function (fn, timeout, skipOnEnterAndKeys) {
-  var _options = {
+$.fn[pluginName] = function(fn, timeout, skipOnEnterAndKeys) {
+  const _options = {
     fn: fn,
     timeout: timeout,
     skipOnEnterAndKeys: typeof skipOnEnterAndKeys !== 'undefined' && skipOnEnterAndKeys
-  }
-  return this.each(function () {
+  };
+  return this.each(function() {
     if (!$.data(this, 'plugin_' + pluginName)) {
       $.data(this, 'plugin_' + pluginName, new Plugin(this, _options));
-    }
-    else {
+    } else {
       $.data(this, 'plugin_' + pluginName).setOptions(_options);
     }
   });
-}
+};

+ 849 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.filechooser.js

@@ -0,0 +1,849 @@
+// 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.
+
+import $ from 'jquery';
+import qq from 'ext/fileuploader.custom';
+
+import huePubSub from '../../utils/huePubSub';
+
+/*
+ * jHue fileChooser plugin
+ */
+
+const pluginName = 'jHueFileChooser',
+  defaults = {
+    initialPath: '',
+    forceRefresh: false,
+    errorRedirectPath: '',
+    createFolder: true,
+    uploadFile: true,
+    selectFolder: false,
+    suppressErrors: false,
+    displayOnlyFolders: false,
+    showExtraHome: false,
+    extraHomeProperties: {},
+    filterExtensions: '',
+    labels: {
+      BACK: 'Back',
+      SELECT_FOLDER: 'Select this folder',
+      CREATE_FOLDER: 'Create folder',
+      FOLDER_NAME: 'Folder name',
+      CANCEL: 'Cancel',
+      FILE_NOT_FOUND: 'The file has not been found',
+      UPLOAD_FILE: 'Upload a file',
+      FAILED: 'Failed',
+      HOME: 'Home'
+    },
+    filesystems: ['hdfs'],
+    filesysteminfo: {
+      '': {
+        scheme: '',
+        root: '/',
+        home: '/?default_to_home',
+        icon: {
+          brand: 'fa-files-o',
+          home: 'fa-home'
+        },
+        label: {
+          home: 'home',
+          name: 'HDFS'
+        }
+      },
+      hdfs: {
+        scheme: '',
+        root: '/',
+        home: '/?default_to_home',
+        icon: {
+          brand: 'fa-files-o',
+          home: 'fa-home'
+        },
+        label: {
+          home: 'home',
+          name: 'HDFS'
+        }
+      },
+      s3a: {
+        scheme: 's3a',
+        root: 's3a://',
+        home: 's3a://',
+        icon: {
+          brand: 'fa-cubes',
+          home: 'fa-cubes'
+        },
+        label: {
+          home: '',
+          name: 'S3'
+        }
+      },
+      adl: {
+        scheme: 'adl',
+        root: 'adl:/',
+        home: 'adl:/',
+        icon: {
+          svg: {
+            brand: '#hi-adls',
+            home: '#hi-adls'
+          },
+          brand: 'fa-windows',
+          home: 'fa-windows'
+        },
+        label: {
+          home: '',
+          name: 'ADLS'
+        }
+      }
+    },
+    fsSelected: 'hdfs',
+    user: '',
+    onNavigate: function() {},
+    onFileChoose: function() {},
+    onFolderChoose: function() {},
+    onFolderChange: function() {},
+    onError: function() {}
+  },
+  STORAGE_PREFIX = 'hueFileBrowserLastPathForUser_';
+
+function Plugin(element, options) {
+  this.element = element;
+  $(element).data('jHueFileChooser', this);
+
+  this.options = $.extend({}, defaults, { user: LOGGED_USERNAME }, options);
+  this.options.labels = $.extend(
+    {},
+    defaults.labels,
+    HUE_I18n.jHueFileChooser,
+    options ? options.labels : {}
+  );
+  this._defaults = defaults;
+  this._name = pluginName;
+  this.previousPath = '';
+  this.init();
+}
+
+Plugin.prototype.setOptions = function(options) {
+  const self = this;
+  self.options = $.extend({}, defaults, { user: LOGGED_USERNAME }, options);
+  self.options.labels = $.extend(
+    {},
+    defaults.labels,
+    HUE_I18n.jHueFileChooser,
+    options ? options.labels : {}
+  );
+  const initialPath = $.trim(self.options.initialPath);
+  const scheme = initialPath && initialPath.substring(0, initialPath.indexOf(':'));
+  if (scheme && scheme.length) {
+    self.options.fsSelected = scheme;
+  }
+
+  $(self.element)
+    .find('.filechooser-services li')
+    .removeClass('active');
+  $(self.element)
+    .find('.filechooser-services li[data-fs="' + self.options.fsSelected + '"]')
+    .addClass('active');
+
+  if (self.options.forceRefresh) {
+    if (initialPath != '') {
+      self.navigateTo(self.options.initialPath);
+    } else if (
+      $.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected) != null
+    ) {
+      self.navigateTo($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected));
+    } else {
+      self.navigateTo('/?default_to_home');
+    }
+  } else if (initialPath != '') {
+    self.navigateTo(self.options.initialPath);
+  } else if ($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected) != null) {
+    self.navigateTo($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected));
+  }
+};
+
+function getScheme(path) {
+  const index = path.indexOf('://');
+  return index >= 0 ? path.substring(0, index) : 'hdfs';
+}
+
+function getFs(scheme) {
+  if (scheme === 'adl') {
+    return 'adls';
+  } else if (scheme === 's3a') {
+    return 's3';
+  } else if (!scheme || scheme === 'hdfs') {
+    return 'hdfs';
+  } else {
+    return scheme;
+  }
+}
+
+Plugin.prototype.setFileSystems = function(filesystems) {
+  const self = this;
+  let filters, filesystemsFiltered;
+  self.options.filesystems = [];
+  Object.keys(filesystems).forEach(k => {
+    if (filesystems[k]) {
+      self.options.filesystems.push(k);
+    }
+  });
+  self.options.filesystems.sort();
+  if (self.options.filesystemsFilter) {
+    filters = self.options.filesystemsFilter.reduce((filters, fs) => {
+      filters[fs] = true;
+      return filters;
+    }, {});
+    filesystemsFiltered = self.options.filesystems.filter(fs => {
+      return filters[fs];
+    });
+  } else {
+    filesystemsFiltered = self.options.filesystems;
+  }
+
+  $(self.element).data('fs', filesystemsFiltered);
+  if (filesystemsFiltered.length > 1) {
+    const $ul = $('<ul>')
+      .addClass('nav nav-list')
+      .css('border', 'none');
+    filesystemsFiltered.forEach(fs => {
+      const filesysteminfo = self.options.filesysteminfo;
+      const $li = $('<li>')
+        .attr('data-fs', fs)
+        .addClass(self.options.fsSelected === fs ? 'active' : '')
+        .html(
+          '<a class="pointer" style="padding-left: 6px">' +
+            (filesysteminfo[fs] ? filesysteminfo[fs].label.name : fs.toUpperCase()) +
+            '</a>'
+        );
+      $li.on('click', function() {
+        $(this)
+          .siblings()
+          .removeClass('active');
+        $(this).addClass('active');
+        self.options.fsSelected = fs;
+        const storedPath = $.totalStorage(
+          STORAGE_PREFIX + self.options.user + self.options.fsSelected
+        );
+        if (storedPath !== null) {
+          if (filesysteminfo[fs] && storedPath.toLowerCase().indexOf(fs) === -1) {
+            self.navigateTo(filesysteminfo[fs].home);
+          } else {
+            self.navigateTo(storedPath);
+          }
+        } else {
+          self.navigateTo(filesysteminfo[fs] ? filesysteminfo[fs].home : '/?default_to_home');
+        }
+      });
+      $li.appendTo($ul);
+    });
+    $(self.element)
+      .find('.filechooser-services')
+      .empty()
+      .width(80);
+    $(self.element)
+      .find('.filechooser-tree')
+      .width(480)
+      .css('paddingLeft', '6px')
+      .css('borderLeft', '1px solid #EEE')
+      .css('marginLeft', '80px')
+      .css('min-height', '330px');
+    $ul.appendTo($(self.element).find('.filechooser-services'));
+  }
+};
+
+//TODO: refactor this method to template
+Plugin.prototype.navigateTo = function(path) {
+  const _parent = this;
+  $(_parent.element)
+    .find('.filechooser-tree')
+    .html('<i style="font-size: 24px; color: #DDD" class="fa fa-spinner fa-spin"></i>');
+  let pageSize = '?pagesize=1000';
+  if (path.indexOf('?') > -1) {
+    pageSize = pageSize.replace(/\?/, '&');
+  }
+  $.getJSON('/filebrowser/view=' + path + pageSize, data => {
+    $(_parent.element)
+      .find('.filechooser-tree')
+      .empty();
+
+    path = data.current_dir_path || path; // use real path.
+    const _flist = $('<ul>')
+      .addClass('unstyled')
+      .css({
+        height: '260px',
+        'overflow-y': 'auto'
+      });
+    const $homeBreadcrumb = $('<ul>')
+      .addClass('hue-breadcrumbs')
+      .css({
+        padding: '0',
+        marginLeft: '0',
+        float: 'left',
+        'white-space': 'nowrap'
+      });
+    const _home = $('<li>');
+    //var filesysteminfo = self.options.filesysteminfo;
+    const fs = _parent.options.filesysteminfo[_parent.options.fsSelected || 'hdfs'];
+    const el = fs.icon.svg
+      ? '<svg class="hi"><use xlink:href="' + fs.icon.svg.home + '"></use></svg>'
+      : '<i class="fa ' + fs.icon.home + '"></i> ' + fs.label.home;
+    const _homelink = $('<a>')
+      .addClass('nounderline')
+      .html(el)
+      .css('cursor', 'pointer')
+      .click(() => {
+        _parent.navigateTo(fs.home);
+      });
+
+    _homelink.appendTo(_home);
+    _home.appendTo($homeBreadcrumb);
+
+    $('<span>')
+      .addClass('divider')
+      .css('margin-right', '20px')
+      .appendTo(_home);
+
+    if (data.error || (data.title != null && data.title == 'Error')) {
+      $homeBreadcrumb.appendTo($(_parent.element).find('.filechooser-tree'));
+      $("<div class='clearfix'>").appendTo($(_parent.element).find('.filechooser-tree'));
+      const _errorMsg = $('<div>')
+        .addClass('alert')
+        .addClass('alert-error')
+        .text(data.message ? data.message : data.error);
+      _errorMsg.appendTo($(_parent.element).find('.filechooser-tree'));
+      //TODO: allow user to user breadcrums when there is an error
+      const _previousLink = $('<a>')
+        .addClass('btn')
+        .text(_parent.options.labels.BACK)
+        .click(() => {
+          function getParentPath(path) {
+            if (!path) {
+              return path;
+            }
+            const indexFirst = path.indexOf('/');
+            const indexLast = path.lastIndexOf('/');
+            return indexLast - indexFirst > 1 && indexLast > 0
+              ? path.substring(0, indexLast + 1)
+              : path;
+          }
+          const next =
+            path !== _parent.previousPath && getScheme(path) === getScheme(_parent.previousPath)
+              ? _parent.previousPath
+              : getParentPath(path);
+          _parent.options.onFolderChange(next);
+          _parent.navigateTo(next);
+        });
+      _previousLink.appendTo($(_parent.element).find('.filechooser-tree'));
+    } else {
+      if (data.type == 'file') {
+        _parent.navigateTo(data.view.dirname);
+        return;
+      }
+      $.totalStorage(STORAGE_PREFIX + _parent.options.user + _parent.options.fsSelected, path);
+      _parent.previousPath = path;
+      _parent.options.onNavigate(_parent.previousPath);
+
+      const $search = $('<div>')
+        .html(
+          '<i class="fa fa-refresh inactive-action pointer" style="position: absolute; top: 3px; margin-left: -16px"></i> <i class="fa fa-search inactive-action pointer" style="position: absolute; top: 3px"></i><input type="text" class="small-search" style="display: none; width: 0; padding: 2px; padding-left: 20px">'
+        )
+        .css({
+          position: 'absolute',
+          right: '20px',
+          'background-color': '#FFF'
+        });
+
+      const slideOutInput = () => {
+        $search.find('input').animate(
+          {
+            width: '0'
+          },
+          100,
+          () => {
+            $search.find('input').hide();
+            $search.find('.fa-refresh').show();
+          }
+        );
+      };
+
+      const $searchInput = $search.find('input');
+      const tog = v => (v ? 'addClass' : 'removeClass');
+      $searchInput.addClass('clearable');
+      $searchInput
+        .on('input', function() {
+          $searchInput[tog(this.value)]('x');
+        })
+        .on('mousemove', function(e) {
+          $searchInput[tog(this.offsetWidth - 18 < e.clientX - this.getBoundingClientRect().left)](
+            'onX'
+          );
+        })
+        .on('click', function(e) {
+          if (this.offsetWidth - 18 < e.clientX - this.getBoundingClientRect().left) {
+            $searchInput.removeClass('x onX').val('');
+          }
+        });
+      if (!isIE11) {
+        $searchInput.on('blur', e => {
+          if ($searchInput.val() === '') {
+            slideOutInput();
+          }
+        });
+      }
+
+      $search.find('.fa-search').on('click', () => {
+        if ($searchInput.is(':visible')) {
+          slideOutInput();
+        } else {
+          $search.find('.fa-refresh').hide();
+          $searchInput.show().animate(
+            {
+              width: '100px'
+            },
+            100,
+            () => {
+              $searchInput.focus();
+            }
+          );
+        }
+      });
+
+      $search.find('.fa-refresh').on('click', () => {
+        _parent.navigateTo(path);
+      });
+
+      $search.appendTo($(_parent.element).find('.filechooser-tree'));
+
+      const $scrollingBreadcrumbs = $('<ul>')
+        .addClass('hue-breadcrumbs editable-breadcrumbs')
+        .css({
+          padding: '0',
+          marginLeft: '10px',
+          marginBottom: '0',
+          paddingRight: '10px',
+          float: 'left',
+          width: '300px',
+          'overflow-x': 'scroll',
+          'overflow-y': 'hidden',
+          'white-space': 'nowrap'
+        });
+
+      if (ko && ko.bindingHandlers.delayedOverflow) {
+        ko.bindingHandlers.delayedOverflow.init($scrollingBreadcrumbs[0]);
+      }
+
+      if (_parent.options.showExtraHome) {
+        const _extraHome = $('<li>');
+        const _extraHomelink = $('<a>')
+          .addClass('nounderline')
+          .html(
+            '<i class="fa ' +
+              _parent.options.extraHomeProperties.icon +
+              '"></i> ' +
+              _parent.options.extraHomeProperties.label
+          )
+          .css('cursor', 'pointer')
+          .click(() => {
+            _parent.navigateTo(_parent.options.extraHomeProperties.path);
+          });
+        _extraHomelink.appendTo(_extraHome);
+        $('<span>')
+          .addClass('divider')
+          .css('margin-right', '20px')
+          .appendTo(_extraHome);
+        _extraHome.appendTo($scrollingBreadcrumbs);
+      }
+
+      const $hdfsAutocomplete = $('<input type="text">')
+        .addClass('editable-breadcrumb-input')
+        .val(path)
+        .hide();
+
+      $scrollingBreadcrumbs.click(function(e) {
+        if ($(e.target).is('ul') || $(e.target).hasClass('spacer')) {
+          $(this).hide();
+          $hdfsAutocomplete.show().focus();
+        }
+      });
+
+      const $editBreadcrumbs = $('<li>').css('marginRight', '2px');
+      const $crumbLink = $('<span>').addClass('spacer');
+      $crumbLink.html('&nbsp;').appendTo($editBreadcrumbs);
+      $editBreadcrumbs.appendTo($scrollingBreadcrumbs);
+      if (typeof data.breadcrumbs != 'undefined' && data.breadcrumbs != null) {
+        const _bLength = data.breadcrumbs.length;
+        $(data.breadcrumbs).each((cnt, crumb) => {
+          const _crumb = $('<li>');
+          const _crumbLink = $('<a>');
+          const _crumbLabel = crumb.label != null && crumb.label != '' ? crumb.label : '/';
+          _crumbLink
+            .attr('href', 'javascript:void(0)')
+            .text(_crumbLabel)
+            .appendTo(_crumb);
+          if (cnt < _bLength - 1) {
+            if (cnt > 0) {
+              $('<span>')
+                .addClass('divider')
+                .text('/')
+                .appendTo(_crumb);
+            } else {
+              $('<span>')
+                .html('&nbsp;')
+                .appendTo(_crumb);
+            }
+          }
+          _crumb.click(() => {
+            const _url = crumb.url != null && crumb.url != '' ? crumb.url : '/';
+            _parent.options.onFolderChange(_url);
+            _parent.navigateTo(_url);
+          });
+          _crumb.appendTo($scrollingBreadcrumbs);
+        });
+      }
+      $homeBreadcrumb.appendTo($(_parent.element).find('.filechooser-tree'));
+      $scrollingBreadcrumbs.appendTo($(_parent.element).find('.filechooser-tree'));
+      $hdfsAutocomplete.appendTo($(_parent.element).find('.filechooser-tree'));
+
+      $hdfsAutocomplete.jHueHdfsAutocomplete({
+        home: '/user/' + _parent.options.user + '/',
+        skipEnter: true,
+        skipKeydownEvents: true,
+        onEnter: function(el) {
+          const _url = el.val();
+          _parent.options.onFolderChange(_url);
+          _parent.navigateTo(_url);
+          $('#jHueHdfsAutocomplete').hide();
+        },
+        onBlur: function() {
+          $hdfsAutocomplete.hide();
+          $scrollingBreadcrumbs.show();
+        },
+        smartTooltip: _parent.options.labels.SMART_TOOLTIP
+      });
+
+      $('<div>')
+        .addClass('clearfix')
+        .appendTo($(_parent.element).find('.filechooser-tree'));
+
+      const resizeBreadcrumbs = window.setInterval(() => {
+        if ($homeBreadcrumb.is(':visible') && $homeBreadcrumb.width() > 0) {
+          window.clearInterval(resizeBreadcrumbs);
+          $scrollingBreadcrumbs.width(
+            $(_parent.element)
+              .find('.filechooser-tree')
+              .width() -
+              $homeBreadcrumb.width() -
+              65
+          );
+        }
+      }, 100);
+
+      $(data.files).each((cnt, file) => {
+        let _addFile = file.name !== '.';
+        if (_parent.options.filterExtensions != '' && file.type == 'file') {
+          const _allowedExtensions = _parent.options.filterExtensions.split(',');
+          const _fileExtension = file.name
+            .split('.')
+            .pop()
+            .toLowerCase();
+          _addFile = _allowedExtensions.indexOf(_fileExtension) > -1;
+        }
+        if (_addFile) {
+          const _f = $('<li>');
+          const _flink = $('<a>');
+
+          if (file.type == 'dir') {
+            _flink.attr('href', 'javascript:void(0)');
+            if (
+              file.path.toLowerCase().indexOf('s3a://') == 0 &&
+              (file.path.substr(6).indexOf('/') > -1 || file.path.substr(6) == '')
+            ) {
+              _flink.text(' ' + (cnt > 0 ? file.name : '..'));
+            } else {
+              _flink.text(' ' + (file.name != '' ? file.name : '..'));
+            }
+            if (_flink.text() !== ' ..') {
+              _f.addClass('file-list-item');
+            }
+            _flink.appendTo(_f);
+            if (
+              file.path.toLowerCase().indexOf('s3a://') == 0 &&
+              file.path.substr(5).indexOf('/') == -1
+            ) {
+              $("<i class='fa fa-cloud'></i>").prependTo(_flink);
+            } else {
+              $("<i class='fa fa-folder'></i>").prependTo(_flink);
+            }
+            _flink.click(() => {
+              _parent.options.onFolderChange(file.path);
+              _parent.navigateTo(file.path);
+            });
+          }
+          if (file.type == 'file' && !_parent.options.displayOnlyFolders) {
+            _f.addClass('file-list-item');
+            _flink
+              .attr('href', 'javascript:void(0)')
+              .text(' ' + (file.name != '' ? file.name : '..'))
+              .appendTo(_f);
+            $("<i class='fa fa-file-o'></i>").prependTo(_flink);
+            _flink.click(() => {
+              _parent.options.onFileChoose(file.path);
+            });
+          }
+          _f.appendTo(_flist);
+        }
+      });
+
+      _flist.appendTo($(_parent.element).find('.filechooser-tree'));
+
+      $searchInput.jHueDelayedInput(() => {
+        const filter = $searchInput.val().toLowerCase();
+        let results = 0;
+        $(_parent.element)
+          .find('.filechooser-tree .no-results')
+          .hide();
+        $(_parent.element)
+          .find('.filechooser-tree .file-list-item')
+          .each(function() {
+            if (
+              $(this)
+                .text()
+                .toLowerCase()
+                .indexOf(filter) > -1
+            ) {
+              $(this).show();
+              results++;
+            } else {
+              $(this).hide();
+            }
+          });
+        if (results == 0) {
+          $(_parent.element)
+            .find('.filechooser-tree .no-results')
+            .show();
+        }
+      }, 300);
+
+      const _actions = $('<div>').addClass('jHueFilechooserActions');
+      let _showActions = false;
+      let _uploadFileBtn;
+      let _createFolderBtn;
+      let _selectFolderBtn;
+      if (_parent.options.uploadFile) {
+        _uploadFileBtn = $('<div>')
+          .attr('id', 'file-uploader')
+          .addClass('fileChooserActionUploader');
+        _uploadFileBtn.appendTo(_actions);
+        _showActions = true;
+        initUploader(path, _parent, _uploadFileBtn, _parent.options.labels);
+      }
+      if (_parent.options.selectFolder) {
+        _selectFolderBtn = $('<a>')
+          .addClass('btn')
+          .text(_parent.options.labels.SELECT_FOLDER);
+        if (_parent.options.uploadFile) {
+          _selectFolderBtn.css('margin-top', '10px');
+        }
+        _selectFolderBtn.appendTo(_actions);
+        _showActions = true;
+        _selectFolderBtn.click(() => {
+          _parent.options.onFolderChoose(path);
+        });
+      }
+      $('<span> </span>').appendTo(_actions);
+      if (_parent.options.createFolder) {
+        _createFolderBtn = $('<a>')
+          .addClass('btn')
+          .text(_parent.options.labels.CREATE_FOLDER);
+        if (_parent.options.uploadFile) {
+          _createFolderBtn.css('margin-top', '10px');
+        }
+        _createFolderBtn.appendTo(_actions);
+        _showActions = true;
+        const _createFolderDetails = $('<form>')
+          .css({ 'margin-top': '10px', position: 'fixed' })
+          .addClass('form-inline');
+        _createFolderDetails.hide();
+        const _folderName = $('<input>')
+          .attr('type', 'text')
+          .attr('placeholder', _parent.options.labels.FOLDER_NAME)
+          .appendTo(_createFolderDetails);
+        $('<span> </span>').appendTo(_createFolderDetails);
+        const _folderBtn = $('<input>')
+          .attr('type', 'button')
+          .attr('value', _parent.options.labels.CREATE_FOLDER)
+          .addClass('btn primary')
+          .appendTo(_createFolderDetails);
+        $('<span> </span>').appendTo(_createFolderDetails);
+        const _folderCancel = $('<input>')
+          .attr('type', 'button')
+          .attr('value', _parent.options.labels.CANCEL)
+          .addClass('btn')
+          .appendTo(_createFolderDetails);
+        _folderCancel.click(() => {
+          if (_uploadFileBtn) {
+            _uploadFileBtn.removeClass('disabled');
+          }
+          _createFolderBtn.removeClass('disabled');
+          _createFolderDetails.slideUp();
+        });
+        _folderBtn.click(() => {
+          if (_folderName.val().length > 0) {
+            $.ajax({
+              type: 'POST',
+              url: '/filebrowser/mkdir',
+              data: {
+                name: _folderName.val(),
+                path: path
+              },
+              success: function(xhr, status) {
+                if (status == 'success') {
+                  _parent.navigateTo(path);
+                  if (_uploadFileBtn) {
+                    _uploadFileBtn.removeClass('disabled');
+                  }
+                  _createFolderBtn.removeClass('disabled');
+                  _createFolderDetails.slideUp();
+                }
+              },
+              error: function(xhr) {
+                $(document).trigger('error', xhr.responseText);
+              }
+            });
+          }
+        });
+
+        _createFolderDetails.appendTo(_actions);
+
+        _createFolderBtn.click(() => {
+          if (_uploadFileBtn) {
+            _uploadFileBtn.addClass('disabled');
+          }
+          _createFolderBtn.addClass('disabled');
+          _createFolderDetails.slideDown();
+        });
+      }
+      if (_showActions) {
+        _actions.appendTo($(_parent.element).find('.filechooser-tree'));
+      }
+
+      window.setTimeout(() => {
+        $(_parent.element)
+          .parent()
+          .scrollTop(0);
+        $scrollingBreadcrumbs.animate({
+          scrollLeft: $scrollingBreadcrumbs.width()
+        });
+      }, 0);
+    }
+  }).fail(e => {
+    if (!_parent.options.suppressErrors) {
+      $(document).trigger('info', _parent.options.labels.FILE_NOT_FOUND);
+      _parent.options.onError();
+    }
+    if (e.status === 404 || e.status === 500) {
+      const fs = _parent.options.filesysteminfo[_parent.options.fsSelected || 'hdfs'];
+      _parent.navigateTo(
+        _parent.options.errorRedirectPath !== '' ? _parent.options.errorRedirectPath : fs.home
+      );
+    } else {
+      console.error(e);
+      $(document).trigger('error', e.statusText);
+    }
+  });
+};
+
+let num_of_pending_uploads = 0;
+
+function initUploader(path, _parent, el, labels) {
+  new qq.FileUploader({
+    element: el[0],
+    action: '/filebrowser/upload/file',
+    params: {
+      dest: path,
+      fileFieldLabel: 'hdfs_file'
+    },
+    onComplete: function(id, fileName, responseJSON) {
+      num_of_pending_uploads--;
+      if (responseJSON.status == -1) {
+        $(document).trigger('error', responseJSON.data);
+      } else if (!num_of_pending_uploads) {
+        _parent.navigateTo(path);
+        huePubSub.publish('assist.' + getFs(getScheme(path)) + '.refresh');
+      }
+    },
+    onSubmit: function(id, fileName) {
+      num_of_pending_uploads++;
+    },
+    template:
+      '<div class="qq-uploader">' +
+      '<div class="qq-upload-drop-area"><span></span></div>' +
+      '<div class="qq-upload-button">' +
+      labels.UPLOAD_FILE +
+      '</div><br>' +
+      '<ul class="qq-upload-list"></ul>' +
+      '</div>',
+    fileTemplate:
+      '<li>' +
+      '<span class="qq-upload-file"></span>' +
+      '<span class="qq-upload-spinner"></span>' +
+      '<span class="qq-upload-size"></span>' +
+      '<a class="qq-upload-cancel" href="#">' +
+      labels.CANCEL +
+      '</a>' +
+      '<span class="qq-upload-failed-text">' +
+      labels.FAILED +
+      '</span>' +
+      '</li>',
+    debug: false
+  });
+}
+
+Plugin.prototype.init = function() {
+  const self = this;
+  $(self.element)
+    .empty()
+    .html(
+      '<div class="filechooser-container" style="position: relative"><div class="filechooser-services" style="position: absolute"></div><div class="filechooser-tree" style="width: 560px"></div></div>'
+    );
+  $.post('/filebrowser/api/get_filesystems', data => {
+    const initialPath = $.trim(self.options.initialPath);
+    const scheme = initialPath && initialPath.substring(0, initialPath.indexOf(':'));
+    if (data && data.status === 0) {
+      if (scheme && scheme.length && data.filesystems[scheme]) {
+        self.options.fsSelected = scheme;
+      }
+      self.setFileSystems(data.filesystems);
+    }
+    if (initialPath != '') {
+      self.navigateTo(self.options.initialPath);
+    } else if (
+      $.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected) != null
+    ) {
+      self.navigateTo($.totalStorage(STORAGE_PREFIX + self.options.user + self.options.fsSelected));
+    } else {
+      self.navigateTo('/?default_to_home');
+    }
+  });
+};
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    if (!$.data(this, 'plugin_' + pluginName)) {
+      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+    } else {
+      $.data(this, 'plugin_' + pluginName).setOptions(options);
+    }
+  });
+};

+ 406 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.hdfs.autocomplete.js

@@ -0,0 +1,406 @@
+// 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.
+
+import $ from 'jquery';
+
+import hueUtils from '../../utils/hueUtils';
+
+/*
+ * jHue HDFS autocomplete plugin
+ * augment a textbox into an HDFS autocomplete
+ */
+
+const pluginName = 'jHueHdfsAutocomplete',
+  defaults = {
+    home: '/',
+    onEnter: function() {},
+    onBlur: function() {},
+    onPathChange: function() {},
+    smartTooltip: '',
+    smartTooltipThreshold: 10, // needs 10 up/down or click actions and no tab to activate the smart tooltip
+    showOnFocus: false,
+    skipKeydownEvents: false,
+    skipEnter: false,
+    skipScrollEvent: false,
+    zIndex: 33000,
+    root: '/',
+    isS3: false
+  };
+
+function Plugin(element, options) {
+  this.element = element;
+  this.options = $.extend({}, defaults, options);
+  this._defaults = defaults;
+  this._name = pluginName;
+  this.init();
+}
+
+Plugin.prototype.init = function() {
+  const _this = this;
+  const _el = $(_this.element);
+  _el.addClass('jHueAutocompleteElement');
+  _el.attr('autocomplete', 'off'); // prevents default browser behavior
+
+  // creates autocomplete popover
+  if ($('#jHueHdfsAutocomplete').length == 0) {
+    $('<div>')
+      .attr('id', 'jHueHdfsAutocomplete')
+      .addClass('jHueAutocomplete popover')
+      .attr(
+        'style',
+        'position:absolute;display:none;max-width:1000px;z-index:' + _this.options.zIndex
+      )
+      .html(
+        '<div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p><ul class="unstyled"></ul></p></div></div>'
+      )
+      .appendTo($(HUE_CONTAINER));
+  }
+
+  function setHueBreadcrumbCaretAtEnd(element) {
+    const elemLength = element.value.length;
+    if (document.selection) {
+      element.focus();
+      const _oSel = document.selection.createRange();
+      _oSel.moveStart('character', -elemLength);
+      _oSel.moveStart('character', elemLength);
+      _oSel.moveEnd('character', 0);
+      _oSel.select();
+    } else if (element.selectionStart || element.selectionStart == '0') {
+      element.selectionStart = elemLength;
+      element.selectionEnd = elemLength;
+      element.focus();
+    }
+  }
+
+  _el.focus(() => {
+    $(document.body).on('contextmenu', e => {
+      e.preventDefault(); // prevents native menu on FF for Mac from being shown
+    });
+    setHueBreadcrumbCaretAtEnd(_this.element);
+  });
+
+  _el.keydown(e => {
+    if (e.keyCode == 9) {
+      e.preventDefault();
+      showHdfsAutocomplete(() => {
+        let path = _el.val();
+        if (path.indexOf('/') > -1) {
+          path = path.substr(path.lastIndexOf('/') + 1);
+        }
+        guessHdfsPath(path);
+      });
+    }
+  });
+
+  function smartTooltipMaker() {
+    if (
+      _this.options.smartTooltip != '' &&
+      typeof $.totalStorage != 'undefined' &&
+      $.totalStorage('jHueHdfsAutocompleteTooltip') != -1
+    ) {
+      let cnt = 0;
+      if ($.totalStorage('jHueHdfsAutocompleteTooltip') != null) {
+        cnt = $.totalStorage('jHueHdfsAutocompleteTooltip') + 1;
+      }
+      $.totalStorage('jHueHdfsAutocompleteTooltip', cnt);
+      if (cnt >= _this.options.smartTooltipThreshold) {
+        _el
+          .tooltip({
+            animation: true,
+            title: _this.options.smartTooltip,
+            trigger: 'manual',
+            placement: 'top'
+          })
+          .tooltip('show');
+        window.setTimeout(() => {
+          _el.tooltip('hide');
+        }, 10000);
+        $.totalStorage('jHueHdfsAutocompleteTooltip', -1);
+      }
+    }
+  }
+
+  if (!_this.options.skipScrollEvent) {
+    $(window).on('scroll', () => {
+      $('#jHueHdfsAutocomplete')
+        .css('top', _el.offset().top + _el.outerHeight() - 1)
+        .css('left', _el.offset().left)
+        .width(_el.outerWidth() - 4);
+    });
+  }
+
+  _el.on('keydown', e => {
+    if (!_this.options.skipKeydownEvents && e.keyCode == 191) {
+      e.preventDefault();
+    }
+    if (e.keyCode == 32 && e.ctrlKey) {
+      e.preventDefault();
+    }
+    if (_this.options.skipEnter && e.keyCode === 13) {
+      e.preventDefault();
+      e.stopPropagation();
+      e.stopImmediatePropagation();
+    }
+  });
+
+  let _hdfsAutocompleteSelectedIndex = -1;
+  let _filterTimeout = -1;
+  _el.keyup(function(e) {
+    window.clearTimeout(_filterTimeout);
+    if ($.inArray(e.keyCode, [38, 40, 13, 32, 191]) == -1) {
+      _hdfsAutocompleteSelectedIndex = -1;
+      _filterTimeout = window.setTimeout(() => {
+        let path = _el.val();
+        if (path.indexOf('/') > -1) {
+          path = path.substr(path.lastIndexOf('/') + 1);
+        }
+        $('#jHueHdfsAutocomplete ul li').show();
+        $('#jHueHdfsAutocomplete ul li').each(function() {
+          if (
+            $(this)
+              .text()
+              .trim()
+              .indexOf(path) != 0
+          ) {
+            $(this).hide();
+          }
+        });
+      }, 500);
+    }
+    if (e.keyCode == 38) {
+      if (_hdfsAutocompleteSelectedIndex <= 0) {
+        _hdfsAutocompleteSelectedIndex = $('#jHueHdfsAutocomplete ul li:visible').length - 1;
+      } else {
+        _hdfsAutocompleteSelectedIndex--;
+      }
+    }
+    if (e.keyCode == 40) {
+      if (_hdfsAutocompleteSelectedIndex == $('#jHueHdfsAutocomplete ul li:visible').length - 1) {
+        _hdfsAutocompleteSelectedIndex = 0;
+      } else {
+        _hdfsAutocompleteSelectedIndex++;
+      }
+    }
+    if (e.keyCode == 38 || e.keyCode == 40) {
+      smartTooltipMaker();
+      $('#jHueHdfsAutocomplete ul li').removeClass('active');
+      $('#jHueHdfsAutocomplete ul li:visible')
+        .eq(_hdfsAutocompleteSelectedIndex)
+        .addClass('active');
+      $('#jHueHdfsAutocomplete .popover-content').scrollTop(
+        $('#jHueHdfsAutocomplete ul li:visible')
+          .eq(_hdfsAutocompleteSelectedIndex)
+          .prevAll().length *
+          $('#jHueHdfsAutocomplete ul li:visible')
+            .eq(_hdfsAutocompleteSelectedIndex)
+            .outerHeight()
+      );
+    }
+    if ((e.keyCode == 32 && e.ctrlKey) || e.keyCode == 191) {
+      smartTooltipMaker();
+      showHdfsAutocomplete();
+    }
+    if (e.keyCode == 13) {
+      if (_hdfsAutocompleteSelectedIndex > -1) {
+        $('#jHueHdfsAutocomplete ul li:visible')
+          .eq(_hdfsAutocompleteSelectedIndex)
+          .click();
+      } else {
+        _this.options.onEnter($(this));
+      }
+      $('#jHueHdfsAutocomplete').hide();
+      _hdfsAutocompleteSelectedIndex = -1;
+    }
+  });
+
+  if (_this.options.showOnFocus) {
+    _el.on('focus', () => {
+      showHdfsAutocomplete();
+    });
+  }
+
+  let _pauseBlur = false;
+
+  _el.blur(() => {
+    if (!_pauseBlur) {
+      $(document.body).off('contextmenu');
+      $('#jHueHdfsAutocomplete').hide();
+      _this.options.onBlur();
+    }
+  });
+
+  const BASE_PATH = '/filebrowser/view=';
+  let _currentFiles = [];
+
+  function showHdfsAutocomplete(callback) {
+    let base = '';
+    let path = _el.val();
+    const hasScheme = path.indexOf(':/') >= 0;
+    const isRelative = !hasScheme && path.charAt(0) !== '/';
+    if (isRelative && _this.options.root) {
+      base += _this.options.root;
+    }
+    const autocompleteUrl = BASE_PATH + base + path;
+    $.getJSON(autocompleteUrl + '?pagesize=1000&format=json', data => {
+      _currentFiles = [];
+      if (data.error == null) {
+        $(data.files).each((cnt, item) => {
+          if (item.name != '.') {
+            let ico = 'fa-file-o';
+            if (item.type == 'dir') {
+              ico = 'fa-folder';
+            }
+            _currentFiles.push(
+              '<li class="hdfsAutocompleteItem" data-value="' +
+                hueUtils.escapeOutput(item.name) +
+                '"><i class="fa ' +
+                ico +
+                '"></i> ' +
+                hueUtils.escapeOutput(item.name) +
+                '</li>'
+            );
+          }
+        });
+        window.setTimeout(() => {
+          $('#jHueHdfsAutocomplete')
+            .css('top', _el.offset().top + _el.outerHeight() - 1)
+            .css('left', _el.offset().left)
+            .width(_el.outerWidth() - 4);
+          $('#jHueHdfsAutocomplete')
+            .find('ul')
+            .empty()
+            .html(_currentFiles.join(''));
+          $('#jHueHdfsAutocomplete')
+            .find('li')
+            .on('click', function(e) {
+              smartTooltipMaker();
+              e.preventDefault();
+              const item = $(this)
+                .text()
+                .trim();
+              if (item == '..') {
+                // one folder up
+                path = path.substring(0, path.lastIndexOf('/'));
+              } else {
+                path = path + (path.charAt(path.length - 1) == '/' ? '' : '/') + item;
+              }
+              _el.val(base + path);
+              if (
+                $(this)
+                  .html()
+                  .indexOf('folder') > -1
+              ) {
+                _el.val(_el.val() + '/');
+                _this.options.onPathChange(_el.val());
+                showHdfsAutocomplete();
+              } else {
+                _this.options.onEnter(_el);
+              }
+            });
+          $('#jHueHdfsAutocomplete').show();
+          setHueBreadcrumbCaretAtEnd(_this.element);
+          if ('undefined' != typeof callback) {
+            callback();
+          }
+        }, 100); // timeout for IE8
+      }
+    });
+  }
+
+  $(document).on('mouseenter', '.hdfsAutocompleteItem', () => {
+    _pauseBlur = true;
+  });
+
+  $(document).on('mouseout', '.hdfsAutocompleteItem', () => {
+    _pauseBlur = false;
+  });
+
+  function guessHdfsPath(lastChars) {
+    const possibleMatches = [];
+    for (let i = 0; i < _currentFiles.length; i++) {
+      if (
+        ($(_currentFiles[i])
+          .text()
+          .trim()
+          .indexOf(lastChars) == 0 ||
+          lastChars == '') &&
+        $(_currentFiles[i])
+          .text()
+          .trim() != '..'
+      ) {
+        possibleMatches.push(_currentFiles[i]);
+      }
+    }
+    if (possibleMatches.length == 1) {
+      _el.val(
+        _el.val() +
+          $(possibleMatches[0])
+            .text()
+            .trim()
+            .substr(lastChars.length)
+      );
+      if (
+        $(possibleMatches[0])
+          .html()
+          .indexOf('folder') > -1
+      ) {
+        _el.val(_el.val() + '/');
+        showHdfsAutocomplete();
+      }
+    } else if (possibleMatches.length > 1) {
+      // finds the longest common prefix
+      const possibleMatchesPlain = [];
+      for (let z = 0; z < possibleMatches.length; z++) {
+        possibleMatchesPlain.push(
+          $(possibleMatches[z])
+            .text()
+            .trim()
+        );
+      }
+      const arr = possibleMatchesPlain.slice(0).sort();
+      const word1 = arr[0];
+      const word2 = arr[arr.length - 1];
+
+      let j = 0;
+      while (word1.charAt(j) == word2.charAt(j)) {
+        ++j;
+      }
+      const match = word1.substring(0, j);
+      _el.val(_el.val() + match.substr(lastChars.length));
+    }
+  }
+};
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, defaults, options);
+};
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    if (!$.data(this, 'plugin_' + pluginName)) {
+      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+    } else {
+      $.data(this, 'plugin_' + pluginName).setOptions(options);
+    }
+  });
+};
+
+$[pluginName] = function(options) {
+  if (typeof console != 'undefined') {
+    console.warn('$(elem).jHueHdfsAutocomplete() is a preferred call method.');
+  }
+  $(options.element).jHueHdfsAutocomplete(options);
+};

+ 741 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.hiveautocomplete.js

@@ -0,0 +1,741 @@
+// 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.
+
+import $ from 'jquery';
+
+import contextCatalog from 'catalog/contextCatalog';
+import dataCatalog from 'catalog/dataCatalog';
+
+/*
+ * jHue generic autocomplete plugin
+ * augment a textbox into an generic hive/solr autocomplete
+ */
+
+const pluginName = 'jHueGenericAutocomplete',
+  defaults = {
+    serverType: 'HIVE',
+    home: '/',
+    skipColumns: false,
+    skipTables: false,
+    onEnter: function() {},
+    onBlur: function() {},
+    onPathChange: function() {},
+    pathChangeLevel: '',
+    smartTooltip: '',
+    smartTooltipThreshold: 10, // needs 10 up/down or click actions and no tab to activate the smart tooltip
+    showOnFocus: false,
+    startingPath: '',
+    rewriteVal: false,
+    searchEverywhere: false,
+    apiHelperUser: '',
+    apiHelperType: '',
+    mainScrollable: $(window)
+  };
+
+function Plugin(element, options) {
+  const self = this;
+  self.element = element;
+  self.options = $.extend({}, defaults, options);
+  self._defaults = defaults;
+  self._name = pluginName;
+
+  self.namespaceDeferred = $.Deferred();
+  self.computeDeferred = $.Deferred();
+
+  if (self.options.namespace) {
+    self.namespaceDeferred.resolve(self.options.namespace);
+  } else {
+    contextCatalog.getNamespaces({ sourceType: options.apiHelperType }).done(context => {
+      if (context.namespaces && context.namespaces.length) {
+        self.namespaceDeferred.resolve(context.namespaces[0]);
+      } else {
+        self.namespaceDeferred.reject();
+      }
+    });
+  }
+  self.namespaceDeferred.done(namespace => {
+    if (
+      !self.options.compute ||
+      !namespace.computes.some(compute => {
+        if (compute.id === self.options.compute.id) {
+          self.computeDeferred.resolve(compute);
+          return true;
+        }
+      })
+    ) {
+      self.computeDeferred.resolve(namespace.computes[0]);
+    }
+  });
+
+  this.init();
+}
+
+Plugin.prototype.init = function() {
+  const self = this;
+  const $el = $(self.element);
+
+  // creates autocomplete popover
+  if ($('#jHueGenericAutocomplete').length === 0) {
+    $('<div>')
+      .attr('id', 'jHueGenericAutocomplete')
+      .addClass('jHueAutocomplete popover')
+      .attr('style', 'position:absolute;display:none;max-width:1000px;z-index:33000')
+      .html(
+        '<div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><ul class="unstyled"></ul></div></div>'
+      )
+      .appendTo(window.HUE_CONTAINER);
+  }
+
+  $el.wrap('<div class="inline">');
+  $el
+    .parent()
+    .append(
+      '<i class="fa fa-spinner fa-spin muted" style="margin-top: 8px; margin-left: -24px; margin-right: 11px; display:none"></i>'
+    );
+
+  function setHueBreadcrumbCaretAtEnd(element) {
+    const elemLength = element.value.length;
+    if (document.selection) {
+      element.focus();
+      const _oSel = document.selection.createRange();
+      _oSel.moveStart('character', -elemLength);
+      _oSel.moveStart('character', elemLength);
+      _oSel.moveEnd('character', 0);
+      _oSel.select();
+    } else if (element.selectionStart || element.selectionStart === '0') {
+      element.selectionStart = elemLength;
+      element.selectionEnd = elemLength;
+      element.focus();
+    }
+  }
+
+  $el.focus(() => {
+    $(document.body).on('contextmenu', e => {
+      e.preventDefault(); // prevents native menu on FF for Mac from being shown
+    });
+    setHueBreadcrumbCaretAtEnd(self.element);
+    _pauseBlur = false;
+  });
+
+  $el.keydown(e => {
+    if (e.keyCode === 9) {
+      e.preventDefault();
+      showAutocomplete(() => {
+        let path = $el.val();
+        if (path.indexOf('.') > -1) {
+          path = path.substr(path.lastIndexOf('.') + 1);
+        }
+        guessHivePath(path);
+      });
+    }
+  });
+
+  function smartTooltipMaker() {
+    if (
+      self.options.smartTooltip !== '' &&
+      typeof $.totalStorage !== 'undefined' &&
+      $.totalStorage('jHueGenericAutocompleteTooltip') !== -1
+    ) {
+      let cnt = 0;
+      if ($.totalStorage('jHueGenericAutocompleteTooltip')) {
+        cnt = $.totalStorage('jHueGenericAutocompleteTooltip') + 1;
+      }
+      $.totalStorage('jHueGenericAutocompleteTooltip', cnt);
+      if (cnt >= self.options.smartTooltipThreshold) {
+        $el
+          .tooltip({
+            animation: true,
+            title: self.options.smartTooltip,
+            trigger: 'manual',
+            placement: 'top'
+          })
+          .tooltip('show');
+        window.setTimeout(() => {
+          $el.tooltip('hide');
+        }, 10000);
+        $.totalStorage('jHueGenericAutocompleteTooltip', -1);
+      }
+    }
+  }
+
+  self.options.mainScrollable.on('scroll', () => {
+    $('#jHueGenericAutocomplete')
+      .css('top', $el.offset().top + $el.outerHeight() - 1)
+      .css('left', $el.offset().left)
+      .width($el.outerWidth() - 4);
+  });
+
+  let validateTimeout = -1;
+  const onPathChange = function(path) {
+    window.clearTimeout(validateTimeout);
+    self.options.onPathChange(path);
+  };
+
+  const validateAndSet = function() {
+    const path = $el.val().split('.');
+    if (path.length > 1) {
+      window.clearTimeout(validateTimeout);
+      validateTimeout = window.setTimeout(() => {
+        $.when(self.namespaceDeferred, self.computeDeferred).done((namespace, compute) => {
+          const target = path.pop();
+          dataCatalog
+            .getChildren({
+              sourceType: self.options.apiHelperType,
+              namespace: namespace,
+              compute: compute,
+              path: path
+            })
+            .done(childEntries => {
+              if (
+                childEntries.some(childEntry => {
+                  return childEntry.name === target;
+                })
+              ) {
+                onPathChange($el.val());
+              }
+            });
+        });
+      }, 500);
+    }
+  };
+
+  let _hiveAutocompleteSelectedIndex = -1;
+  let _filterTimeout = -1;
+  $el.keyup(function(e) {
+    window.clearTimeout(_filterTimeout);
+    validateAndSet();
+    if ($.inArray(e.keyCode, [17, 38, 40, 13, 32, 191]) === -1) {
+      _hiveAutocompleteSelectedIndex = -1;
+      _filterTimeout = window.setTimeout(() => {
+        let path = $el.val();
+        if (path.indexOf('.') > -1) {
+          path = path.substr(path.lastIndexOf('.') + 1);
+        }
+        const $jHueGenericAutocomplete = $('#jHueGenericAutocomplete');
+        $jHueGenericAutocomplete.show();
+        const $jHueGenericAutocompleteLi = $('#jHueGenericAutocomplete ul li');
+        $jHueGenericAutocompleteLi.show();
+        if (path !== '') {
+          $jHueGenericAutocompleteLi.each(function() {
+            if (self.options.searchEverywhere) {
+              if (
+                $(this)
+                  .text()
+                  .trim()
+                  .toLowerCase()
+                  .indexOf(path.toLowerCase()) === -1
+              ) {
+                $(this).hide();
+              }
+            } else if (
+              $(this)
+                .text()
+                .trim()
+                .indexOf(path) !== 0
+            ) {
+              $(this).hide();
+            }
+          });
+          if ($('#jHueGenericAutocomplete ul li:visible').length === 0) {
+            $jHueGenericAutocomplete.hide();
+          }
+        }
+      }, 500);
+    }
+    const $jHueGenericAutocompleteLiVisible = $('#jHueGenericAutocomplete ul li:visible');
+    if (e.keyCode === 38) {
+      if (_hiveAutocompleteSelectedIndex <= 0) {
+        _hiveAutocompleteSelectedIndex = $jHueGenericAutocompleteLiVisible.length - 1;
+      } else {
+        _hiveAutocompleteSelectedIndex--;
+      }
+    }
+    if (e.keyCode === 40) {
+      if (_hiveAutocompleteSelectedIndex === $jHueGenericAutocompleteLiVisible.length - 1) {
+        _hiveAutocompleteSelectedIndex = 0;
+      } else {
+        _hiveAutocompleteSelectedIndex++;
+      }
+    }
+    if (e.keyCode === 38 || e.keyCode === 40) {
+      smartTooltipMaker();
+      $('#jHueGenericAutocomplete ul li').removeClass('active');
+      $jHueGenericAutocompleteLiVisible.eq(_hiveAutocompleteSelectedIndex).addClass('active');
+      $('#jHueGenericAutocomplete .popover-content').scrollTop(
+        $jHueGenericAutocompleteLiVisible.eq(_hiveAutocompleteSelectedIndex).prevAll().length *
+          $jHueGenericAutocompleteLiVisible.eq(_hiveAutocompleteSelectedIndex).outerHeight()
+      );
+    }
+    if ((e.keyCode === 32 && e.ctrlKey) || e.keyCode === 191) {
+      smartTooltipMaker();
+      showAutocomplete();
+    }
+    if (e.keyCode === 13) {
+      _pauseBlur = true;
+      if (_hiveAutocompleteSelectedIndex > -1) {
+        $jHueGenericAutocompleteLiVisible.eq(_hiveAutocompleteSelectedIndex).click();
+      } else {
+        self.options.onEnter($(this));
+      }
+      $('#jHueGenericAutocomplete').hide();
+      _hiveAutocompleteSelectedIndex = -1;
+    }
+  });
+
+  if (self.options.showOnFocus) {
+    $el.on('focus', () => {
+      showAutocomplete();
+    });
+  }
+
+  let _pauseBlur = false;
+
+  $el.blur(() => {
+    if (!_pauseBlur) {
+      $(document.body).off('contextmenu');
+      $('#jHueGenericAutocomplete').hide();
+      self.options.onBlur();
+    }
+  });
+
+  let BASE_PATH = '/beeswax/api/autocomplete/';
+  if (self.options.serverType === 'IMPALA') {
+    BASE_PATH = '/impala/api/autocomplete/';
+  }
+  if (self.options.serverType === 'SOLR') {
+    BASE_PATH = '/indexer/api/autocomplete/';
+  }
+  let _currentFiles = [];
+
+  self.getDatabases = function(callback) {
+    const self = this;
+    $.when(self.namespaceDeferred, self.computeDeferred).done((namespace, compute) => {
+      dataCatalog
+        .getChildren({
+          sourceType: self.options.apiHelperType,
+          namespace: namespace,
+          compute: compute,
+          path: []
+        })
+        .done(dbEntries => {
+          callback(
+            $.map(dbEntries, entry => {
+              return entry.name;
+            })
+          );
+        });
+    });
+  };
+
+  self.getTables = function(database, callback) {
+    const self = this;
+    $.when(self.namespaceDeferred, self.computeDeferred).done((namespace, compute) => {
+      dataCatalog
+        .getEntry({
+          sourceType: self.options.apiHelperType,
+          namespace: namespace,
+          compute: compute,
+          path: [database]
+        })
+        .done(entry => {
+          entry.getSourceMeta().done(callback);
+        });
+    });
+  };
+
+  self.getColumns = function(database, table, callback) {
+    const self = this;
+    $.when(self.namespaceDeferred, self.computeDeferred).done((namespace, compute) => {
+      dataCatalog
+        .getEntry({
+          sourceType: self.options.apiHelperType,
+          namespace: namespace,
+          compute: compute,
+          path: [database, table]
+        })
+        .done(entry => {
+          entry.getSourceMeta().done(callback);
+        });
+    });
+  };
+
+  function autocompleteLogic(autocompleteUrl, data) {
+    if (!data.error) {
+      _currentFiles = [];
+
+      let _ico = '';
+      let _iterable = [];
+      let _isSkipColumns = false;
+      let _isSkipTables = false;
+
+      if (self.options.serverType === 'SOLR') {
+        _iterable = data.collections;
+        _ico = 'fa-search';
+      } else if (data.databases) {
+        // it's a db
+        _iterable = data.databases;
+        _ico = 'fa-database';
+      } else if (data.tables_meta) {
+        // it's a table
+        if (!self.options.skipTables) {
+          _iterable = $.map(data.tables_meta, tablesMeta => {
+            return tablesMeta.name;
+          });
+          _ico = 'fa-table';
+        } else {
+          _isSkipTables = true;
+        }
+      } else if (!self.options.skipColumns) {
+        _iterable = data.columns;
+        _ico = 'fa-columns';
+      } else {
+        _isSkipColumns = true;
+      }
+
+      let firstSolrCollection = false;
+      let firstSolrConfig = false;
+      if (!_isSkipColumns && !_isSkipTables) {
+        $(_iterable).each((cnt, item) => {
+          if (self.options.serverType === 'SOLR') {
+            if (item.isCollection && !firstSolrCollection) {
+              _currentFiles.push(
+                '<li class="hiveAutocompleteItem" data-value="collections.*" title="collections.*"><i class="fa fa-search-plus"></i> collections.*</li>'
+              );
+              _currentFiles.push(
+                '<li class="hiveAutocompleteItem" data-value="admin.collections" title="admin.collections"><i class="fa fa-database"></i> admin.collections</li>'
+              );
+              _currentFiles.push(
+                '<li class="hiveAutocompleteItem" data-value="admin.cores" title="admin.collections"><i class="fa fa-database"></i> admin.cores</li>'
+              );
+              firstSolrCollection = true;
+            }
+            if (item.isConfig) {
+              _ico = 'fa-cog';
+              if (!firstSolrConfig) {
+                _currentFiles.push(
+                  '<li class="hiveAutocompleteItem" data-value="configs.*" title="configs.*"><i class="fa fa-cogs"></i> configs.*</li>'
+                );
+                firstSolrConfig = true;
+              }
+            }
+            _currentFiles.push(
+              '<li class="hiveAutocompleteItem" data-value="' +
+                item.name +
+                '" title="' +
+                item.name +
+                '"><i class="fa ' +
+                _ico +
+                '"></i> ' +
+                item.name +
+                '</li>'
+            );
+          } else {
+            _currentFiles.push(
+              '<li class="hiveAutocompleteItem" data-value="' +
+                item +
+                '" title="' +
+                item +
+                '"><i class="fa ' +
+                _ico +
+                '"></i> ' +
+                item +
+                '</li>'
+            );
+          }
+        });
+
+        const $jHueGenericAutocomplete = $('#jHueGenericAutocomplete');
+        $jHueGenericAutocomplete
+          .css('top', $el.offset().top + $el.outerHeight() - 1)
+          .css('left', $el.offset().left)
+          .width($el.outerWidth() - 4);
+        $jHueGenericAutocomplete
+          .find('ul')
+          .empty()
+          .html(_currentFiles.join(''));
+        $jHueGenericAutocomplete.find('li').on('click', function(e) {
+          smartTooltipMaker();
+          e.preventDefault();
+          const item = $(this)
+            .text()
+            .trim();
+
+          if (
+            $(this)
+              .html()
+              .indexOf('search') > -1 ||
+            $(this)
+              .html()
+              .indexOf('cog') > -1 ||
+            $(this)
+              .html()
+              .indexOf('database') > -1
+          ) {
+            if (
+              $(this)
+                .html()
+                .indexOf('search') > -1 &&
+              $(this)
+                .html()
+                .indexOf('search-plus') === -1
+            ) {
+              $el.val('collections.' + item);
+            } else if (
+              $(this)
+                .html()
+                .indexOf('cog') > -1 &&
+              $(this)
+                .html()
+                .indexOf('cogs') === -1
+            ) {
+              $el.val('configs.' + item);
+            } else {
+              $el.val(item);
+            }
+            if (
+              self.options.pathChangeLevel === '' ||
+              self.options.pathChangeLevel === 'database'
+            ) {
+              onPathChange($el.val());
+            }
+            $('#jHueGenericAutocomplete').hide();
+            _hiveAutocompleteSelectedIndex = -1;
+            self.options.onEnter($el);
+          }
+
+          if (
+            $(this)
+              .html()
+              .indexOf('database') > -1
+          ) {
+            if (self.options.skipTables) {
+              $el.val(item);
+              $('#jHueGenericAutocomplete').hide();
+            } else {
+              $el.val(item + '.');
+            }
+            if (
+              self.options.pathChangeLevel === '' ||
+              self.options.pathChangeLevel === 'database'
+            ) {
+              onPathChange($el.val());
+            }
+            if (!self.options.skipTables) {
+              showAutocomplete();
+            }
+          }
+
+          if (
+            $(this)
+              .html()
+              .indexOf('table') > -1
+          ) {
+            if ($el.val().indexOf('.') > -1) {
+              if ($el.val().match(/\./gi).length === 1) {
+                $el.val($el.val().substring(0, $el.val().lastIndexOf('.') + 1) + item);
+              } else {
+                $el.val($el.val().substring(0, $el.val().indexOf('.') + 1) + item);
+              }
+            } else if (self.options.rewriteVal) {
+              $el.val(item);
+            } else {
+              $el.val($el.val() + item);
+            }
+            if (!self.options.skipColumns) {
+              $el.val($el.val() + '.');
+            }
+            if (self.options.pathChangeLevel === '' || self.options.pathChangeLevel === 'table') {
+              onPathChange($el.val());
+            }
+            if (!self.options.skipColumns) {
+              showAutocomplete();
+            } else {
+              self.options.onEnter($el);
+              $('#jHueGenericAutocomplete').hide();
+              _hiveAutocompleteSelectedIndex = -1;
+            }
+          }
+
+          if (
+            $(this)
+              .html()
+              .indexOf('columns') > -1
+          ) {
+            if ($el.val().match(/\./gi).length > 1) {
+              $el.val($el.val().substring(0, $el.val().lastIndexOf('.') + 1) + item);
+            } else {
+              $el.val($el.val() + '.' + item);
+            }
+            $('#jHueGenericAutocomplete').hide();
+            _hiveAutocompleteSelectedIndex = -1;
+            self.options.onEnter($el);
+          }
+        });
+        $jHueGenericAutocomplete.show();
+        window.setTimeout(() => {
+          setHueBreadcrumbCaretAtEnd(self.element);
+        }, 100);
+      }
+    }
+    $el
+      .parent()
+      .find('.fa-spinner')
+      .hide();
+  }
+
+  function showAutocomplete() {
+    $el
+      .parent()
+      .find('.fa-spinner')
+      .show();
+    let path = $el.val();
+    if (self.options.startingPath !== '') {
+      path = self.options.startingPath + path;
+    }
+    let autocompleteUrl = BASE_PATH;
+
+    if (path !== '' && path.indexOf('.') === -1) {
+      path = '';
+    }
+
+    if (path !== '' && path.lastIndexOf('.') !== path.length - 1) {
+      path = path.substring(0, (self.options.startingPath + $el.val()).lastIndexOf('.'));
+    }
+
+    if (self.options.serverType !== 'SOLR') {
+      autocompleteUrl += path.replace(/\./g, '/');
+    }
+
+    if (self.options.serverType !== 'SOLR' && self.options.apiHelperUser !== '') {
+      const suffix = autocompleteUrl.substr(BASE_PATH.length);
+      if (suffix === '') {
+        self.getDatabases(data => {
+          autocompleteLogic(autocompleteUrl, {
+            databases: data
+          });
+        });
+      } else {
+        const details = suffix.split('/');
+        if (details.length > 1 && details[1] !== '') {
+          self.getColumns(details[0], details[1], data => {
+            let columns = [];
+            if (data.cols || data.extended_columns) {
+              columns = $.map(data.cols ? data.cols : data.extended_columns, item => {
+                return item.name;
+              });
+            } else if (data.columns) {
+              columns = data.columns;
+            }
+            autocompleteLogic(autocompleteUrl, {
+              columns: columns
+            });
+          });
+        } else {
+          self.getTables(details[0], data => {
+            autocompleteLogic(autocompleteUrl, data);
+          });
+        }
+      }
+    } else {
+      $.getJSON(autocompleteUrl, data => {
+        autocompleteLogic(autocompleteUrl, data);
+      });
+    }
+  }
+
+  $(document).on('mouseenter', '.hiveAutocompleteItem', () => {
+    _pauseBlur = true;
+  });
+
+  $(document).on('mouseout', '.hiveAutocompleteItem', () => {
+    _pauseBlur = false;
+  });
+
+  function guessHivePath(lastChars) {
+    const possibleMatches = [];
+    for (let i = 0; i < _currentFiles.length; i++) {
+      if (
+        ($(_currentFiles[i])
+          .text()
+          .trim()
+          .indexOf(lastChars) === 0 ||
+          lastChars === '') &&
+        $(_currentFiles[i])
+          .text()
+          .trim() !== '..'
+      ) {
+        possibleMatches.push(_currentFiles[i]);
+      }
+    }
+    if (possibleMatches.length === 1) {
+      $el.val(
+        $el.val() +
+          $(possibleMatches[0])
+            .text()
+            .trim()
+            .substr(lastChars.length)
+      );
+      if (
+        $(possibleMatches[0])
+          .html()
+          .indexOf('folder') > -1
+      ) {
+        $el.val($el.val() + '/');
+        showAutocomplete();
+      }
+    } else if (possibleMatches.length > 1) {
+      // finds the longest common prefix
+      const possibleMatchesPlain = [];
+      for (let z = 0; z < possibleMatches.length; z++) {
+        possibleMatchesPlain.push(
+          $(possibleMatches[z])
+            .text()
+            .trim()
+        );
+      }
+      const arr = possibleMatchesPlain.slice(0).sort();
+      const word1 = arr[0];
+      const word2 = arr[arr.length - 1];
+      let j = 0;
+      while (word1.charAt(j) === word2.charAt(j)) {
+        ++j;
+      }
+      const match = word1.substring(0, j);
+      $el.val($el.val() + match.substr(lastChars.length));
+    }
+  }
+};
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, defaults, options);
+};
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    if (!$.data(this, 'plugin_' + pluginName)) {
+      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+    } else {
+      $.data(this, 'plugin_' + pluginName).setOptions(options);
+    }
+  });
+};
+
+$[pluginName] = function(options) {
+  if (typeof console !== 'undefined') {
+    console.warn('$(elem).jHueGenericAutocomplete() is a preferred call method.');
+  }
+  $(options.element).jHueGenericAutocomplete(options);
+};

+ 224 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.horizontalscrollbar.js

@@ -0,0 +1,224 @@
+// 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.
+
+import $ from 'jquery';
+
+/*
+ * jHue horizontal scrollbar for dataTables_wrapper
+ *
+ */
+
+const pluginName = 'jHueHorizontalScrollbar',
+  defaults = {};
+
+function Plugin(element, options) {
+  this.element = element;
+  this.options = $.extend({}, defaults, options);
+  this._defaults = defaults;
+  this._name = pluginName;
+  this.init();
+}
+
+function initWhenReady(el) {
+  if ($(el).parents('.dataTables_wrapper').length > 0) {
+    const colWidth = $(el)
+      .find('thead tr th')
+      .outerWidth();
+    if (
+      $(el)
+        .parents('.dataTables_wrapper')
+        .find('.hue-scrollbar-x-rail').length == 0 &&
+      $(el)
+        .parents('.dataTables_wrapper')
+        .width() < $(el).parents('.dataTables_wrapper')[0].scrollWidth
+    ) {
+      $('.hue-scrollbar-x-rail').remove();
+      const scrollbarRail = $('<div>');
+      const scrollbar = $('<div>').addClass('hue-scrollbar-x');
+      scrollbar.width(
+        Math.max(
+          20,
+          $(el)
+            .parents('.dataTables_wrapper')
+            .width() *
+            ($(el)
+              .parents('.dataTables_wrapper')
+              .width() /
+              $(el).parents('.dataTables_wrapper')[0].scrollWidth)
+        )
+      );
+      scrollbar.appendTo(scrollbarRail);
+      try {
+        scrollbar.draggable('destroy');
+      } catch (e) {}
+      let throttleScrollTimeout = -1;
+      scrollbar.draggable({
+        axis: 'x',
+        containment: 'parent',
+        drag: function(e, ui) {
+          $(el)
+            .parents('.dataTables_wrapper')
+            .scrollLeft(
+              ($(el).parents('.dataTables_wrapper')[0].scrollWidth -
+                $(el)
+                  .parents('.dataTables_wrapper')
+                  .width()) *
+                (ui.position.left / (scrollbarRail.width() - $(this).width()))
+            );
+          throttleScrollTimeout = window.setTimeout(() => {
+            $(el)
+              .parents('.dataTables_wrapper')
+              .trigger('scroll');
+          }, 50);
+        }
+      });
+      $(el)
+        .parents('.dataTables_wrapper')
+        .bind('mousewheel', function(e) {
+          const _deltaX = e.deltaX * e.deltaFactor,
+            _deltaY = e.deltaY;
+
+          if (Math.abs(_deltaX) >= Math.abs(_deltaY)) {
+            const self = this;
+            self.scrollLeft += _deltaX;
+            e.preventDefault();
+            e.stopPropagation();
+            e.stopImmediatePropagation();
+            if (self.scrollLeft > 0) {
+              scrollbar.css(
+                'left',
+                (scrollbarRail[0].getBoundingClientRect().width -
+                  scrollbar[0].getBoundingClientRect().width) *
+                  (self.scrollLeft / (self.scrollWidth - self.getBoundingClientRect().width)) +
+                  'px'
+              );
+              window.clearTimeout(throttleScrollTimeout);
+              throttleScrollTimeout = window.setTimeout(() => {
+                $(el)
+                  .parents('.dataTables_wrapper')
+                  .trigger('scroll');
+              }, 50);
+            }
+          }
+        });
+      scrollbarRail.addClass('hue-scrollbar-x-rail').appendTo($(el).parents('.dataTables_wrapper'));
+      scrollbarRail.width(
+        $(el)
+          .parents('.dataTables_wrapper')
+          .width() - colWidth
+      );
+      scrollbarRail.css('marginLeft', colWidth + 'px');
+      if (scrollbarRail.position().top > $(window).height() - 10) {
+        scrollbarRail.css('bottom', '0');
+      }
+      $(el)
+        .parents('.dataTables_wrapper')
+        .bind('scroll_update', () => {
+          scrollbar.css(
+            'left',
+            (scrollbarRail.width() - scrollbar.width()) *
+              ($(el)
+                .parents('.dataTables_wrapper')
+                .scrollLeft() /
+                ($(el).parents('.dataTables_wrapper')[0].scrollWidth -
+                  $(el)
+                    .parents('.dataTables_wrapper')
+                    .width())) +
+              'px'
+          );
+        });
+    } else {
+      if (
+        $(el)
+          .parents('.dataTables_wrapper')
+          .width() === $(el).parents('.dataTables_wrapper')[0].scrollWidth
+      ) {
+        $('.hue-scrollbar-x-rail').hide();
+      } else {
+        $('.hue-scrollbar-x-rail').show();
+      }
+      $(el)
+        .parents('.dataTables_wrapper')
+        .find('.hue-scrollbar-x-rail')
+        .width(
+          $(el)
+            .parents('.dataTables_wrapper')
+            .width() - colWidth
+        );
+      const scrollbar = $(el)
+        .parents('.dataTables_wrapper')
+        .find('.hue-scrollbar-x');
+      scrollbar.width(
+        Math.max(
+          20,
+          $(el)
+            .parents('.dataTables_wrapper')
+            .width() *
+            ($(el)
+              .parents('.dataTables_wrapper')
+              .width() /
+              $(el).parents('.dataTables_wrapper')[0].scrollWidth)
+        )
+      );
+
+      const scrollbarRail = $(el)
+        .parents('.dataTables_wrapper')
+        .find('.hue-scrollbar-x-rail');
+      scrollbarRail.width(
+        $(el)
+          .parents('.dataTables_wrapper')
+          .width() - colWidth
+      );
+      scrollbarRail.css('marginLeft', colWidth + 'px');
+      scrollbar.css(
+        'left',
+        (scrollbarRail.width() - scrollbar.width()) *
+          ($(el)
+            .parents('.dataTables_wrapper')
+            .scrollLeft() /
+            ($(el).parents('.dataTables_wrapper')[0].scrollWidth -
+              $(el)
+                .parents('.dataTables_wrapper')
+                .width())) +
+          'px'
+      );
+    }
+  }
+}
+
+Plugin.prototype.init = function() {
+  const el = this.element;
+
+  const checkWidth = function() {
+    if (
+      $(el)
+        .parents('.dataTables_wrapper')
+        .width() > 0
+    ) {
+      initWhenReady(el);
+    } else {
+      window.setTimeout(checkWidth, 100);
+    }
+  };
+
+  checkWidth();
+};
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+  });
+};

+ 160 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.notify.js

@@ -0,0 +1,160 @@
+// 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.
+
+import $ from 'jquery';
+
+/*
+ * jHue notify plugin
+ *
+ */
+
+const pluginName = 'jHueNotify',
+  TYPES = {
+    INFO: 'INFO',
+    ERROR: 'ERROR',
+    GENERAL: 'GENERAL'
+  },
+  defaults = {
+    level: TYPES.GENERAL,
+    message: '',
+    sticky: false,
+    css: null
+  };
+
+function Plugin(options) {
+  this.options = $.extend({}, defaults, options);
+  this._defaults = defaults;
+  this._name = pluginName;
+  this.show();
+}
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, defaults, options);
+};
+
+Plugin.prototype.show = function() {
+  const _this = this;
+  const MARGIN = 4;
+
+  _this.options.message = _this.options.message.replace(/(<([^>]+)>)/gi, ''); // escape HTML messages
+
+  if (
+    _this.options.message !== '' &&
+    $('.jHueNotify .message')
+      .last()
+      .text() !== _this.options.message
+  ) {
+    const el = $('#jHueNotify').clone();
+    el.removeAttr('id');
+
+    // stops all the current animations and resets the style
+    el.stop(true);
+    el.attr('class', 'alert jHueNotify');
+    el.find('.close').hide();
+
+    if (
+      $('.jHueNotify')
+        .last()
+        .position() != null
+    ) {
+      el.css(
+        'top',
+        $('.jHueNotify')
+          .last()
+          .position().top +
+          $('.jHueNotify')
+            .last()
+            .outerHeight() +
+          MARGIN
+      );
+    }
+
+    if (_this.options.level == TYPES.ERROR) {
+      el.addClass('alert-error');
+    } else if (_this.options.level == TYPES.INFO) {
+      el.addClass('alert-info');
+    }
+    el.find('.message').html('<strong>' + _this.options.message + '</strong>');
+
+    if (_this.options.css != null) {
+      el.attr('style', _this.options.css);
+    }
+
+    el.on('dblclick', () => {
+      el.toggleClass('expanded');
+    });
+
+    if (_this.options.sticky) {
+      el.find('.close')
+        .click(() => {
+          el.fadeOut();
+          el.nextAll('.jHueNotify').animate(
+            {
+              top: '-=' + (el.outerHeight() + MARGIN)
+            },
+            200
+          );
+          el.remove();
+        })
+        .show();
+      el.show();
+    } else {
+      const t = window.setTimeout(() => {
+        el.fadeOut();
+        el.nextAll('.jHueNotify').animate(
+          {
+            top: '-=' + (el.outerHeight() + MARGIN)
+          },
+          200
+        );
+        el.remove();
+      }, 3000);
+      el.click(function() {
+        window.clearTimeout(t);
+        $(this).stop(true);
+        $(this).fadeOut();
+        $(this)
+          .nextAll('.jHueNotify')
+          .animate(
+            {
+              top: '-=' + ($(this).outerHeight() + MARGIN)
+            },
+            200
+          );
+      });
+      el.show();
+    }
+    el.appendTo(HUE_CONTAINER);
+  }
+};
+
+$[pluginName] = function() {};
+
+$[pluginName].info = function(message) {
+  new Plugin({ level: TYPES.INFO, message: message });
+};
+
+$[pluginName].warn = function(message) {
+  new Plugin({ level: TYPES.GENERAL, message: message, sticky: true });
+};
+
+$[pluginName].error = function(message) {
+  new Plugin({ level: TYPES.ERROR, message: message, sticky: true });
+};
+
+$[pluginName].notify = function(options) {
+  new Plugin(options);
+};

+ 36 - 28
desktop/core/src/desktop/js/ext/jquery/hue.jquery.rowselector.js → desktop/core/src/desktop/js/jquery/plugins/jquery.rowselector.js

@@ -13,14 +13,17 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
+import $ from 'jquery';
+
+import huePubSub from '../../utils/huePubSub';
+
 /*
  * jHue row selector plugin
  *
  */
 
-import huePubSub from '../../utils/huePubSub'
-
-var pluginName = "jHueRowSelector",
+const pluginName = 'jHueRowSelector',
   defaults = {};
 
 function Plugin(element, options) {
@@ -31,40 +34,45 @@ function Plugin(element, options) {
   this.init();
 }
 
-Plugin.prototype.setOptions = function (options) {
+Plugin.prototype.setOptions = function(options) {
   this.options = $.extend({}, defaults, options);
 };
 
-Plugin.prototype.init = function () {
-  var _this = this;
-  $(_this.element).closest("tr").click(function (e) {
-    if ($(e.target).data("row-selector-exclude") || $(e.target).closest("td").hasClass("row-selector-exclude")) {
-      return;
-    }
-    if (!$(e.target).is("a")) {
-      var href = $.trim($(_this.element).attr("href"));
-      if (href != "" && href != "#" && href.indexOf("void(0)") == -1) {
-        if (window.IS_HUE_4) {
-          huePubSub.publish('open.link', $(_this.element).attr("href"));
-        }
-        else {
-          location.href = $(_this.element).attr("href");
-        }
+Plugin.prototype.init = function() {
+  const _this = this;
+  $(_this.element)
+    .closest('tr')
+    .click(e => {
+      if (
+        $(e.target).data('row-selector-exclude') ||
+        $(e.target)
+          .closest('td')
+          .hasClass('row-selector-exclude')
+      ) {
+        return;
       }
-      else {
-        $(_this.element).click();
+      if (!$(e.target).is('a')) {
+        const href = $.trim($(_this.element).attr('href'));
+        if (href != '' && href != '#' && href.indexOf('void(0)') == -1) {
+          if (window.IS_HUE_4) {
+            huePubSub.publish('open.link', $(_this.element).attr('href'));
+          } else {
+            location.href = $(_this.element).attr('href');
+          }
+        } else {
+          $(_this.element).click();
+        }
       }
-    }
-  }).css("cursor", "pointer");
+    })
+    .css('cursor', 'pointer');
 };
 
-$.fn[pluginName] = function (options) {
-  return this.each(function () {
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
     if (!$.data(this, 'plugin_' + pluginName)) {
       $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
-    }
-    else {
+    } else {
       $.data(this, 'plugin_' + pluginName).setOptions(options);
     }
   });
-}
+};

+ 184 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.scrollleft.js

@@ -0,0 +1,184 @@
+// 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.
+
+import $ from 'jquery';
+
+import huePubSub from 'utils/huePubSub';
+
+/*
+ * jHue scroll to left plugin
+ * Can be used globally with
+ *   $.jHueScrollLeft()
+ * or with a target for the scroll left
+ *   $(element).jHueScrollLeft()
+ *
+ *   options:
+ *    - threshold: (default 100) value in pixels, scroll amount before the link appears
+ */
+
+const pluginName = 'jHueScrollLeft',
+  defaults = {
+    threshold: 100 // it displays it after 100 px of scroll
+  };
+
+function Plugin(element, options) {
+  this.element = element;
+  this.options = $.extend({}, defaults, options);
+  this._defaults = defaults;
+  this._name = pluginName;
+  if ($(element).attr('jHueLeftScrollified') !== 'true') {
+    this.setupScrollLeft();
+  }
+}
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, defaults, options);
+};
+
+Plugin.prototype.setupScrollLeft = function() {
+  const _this = this;
+  let link = null,
+    isActive = true;
+
+  if ($('#jHueScrollLeftAnchor').length > 0) {
+    // just one scroll up per page
+    link = $('#jHueScrollLeftAnchor');
+    $(document).off('click', '#jHueScrollLeftAnchor');
+  } else {
+    link = $('<a/>')
+      .attr('id', 'jHueScrollLeftAnchor')
+      .addClass('hueAnchor hueAnchorScroller')
+      .attr('href', 'javascript:void(0)')
+      .html("<i class='fa fa-fw fa-chevron-left'></i>")
+      .appendTo(HUE_CONTAINER);
+  }
+
+  $(_this.element).attr('jHueLeftScrollified', 'true');
+
+  if ($(_this.element).is('body')) {
+    setScrollBehavior($(window), $('body, html'));
+  } else {
+    setScrollBehavior($(_this.element), $(_this.element));
+  }
+
+  function positionOtherAnchors() {
+    const upPosition =
+      $('#jHueScrollUpAnchor')
+        .css('right')
+        .replace(/px/gi, '') * 1;
+    let right = upPosition - 30;
+    if ($('#jHueScrollUpAnchor').is(':visible')) {
+      right = upPosition;
+    }
+
+    if ($('#jHueScrollLeftAnchor').is(':visible')) {
+      $('#jHueScrollLeftAnchor').css('right', right + 50 + 'px');
+      right += 50;
+    }
+
+    $('.hue-datatable-search').css('right', right + 50 + 'px');
+  }
+
+  function setScrollBehavior(scrolled, scrollable) {
+    scrolled.scroll(() => {
+      if (scrolled.scrollLeft() > _this.options.threshold) {
+        if (link.is(':hidden')) {
+          positionOtherAnchors();
+          if (isActive) {
+            link.fadeIn(200, positionOtherAnchors);
+          }
+        }
+        if (
+          $(_this.element).data('lastScrollLeft') == null ||
+          $(_this.element).data('lastScrollLeft') < scrolled.scrollLeft()
+        ) {
+          $('#jHueScrollLeftAnchor').data('caller', scrollable);
+        }
+        $(_this.element).data('lastScrollLeft', scrolled.scrollTop());
+      } else {
+        checkForAllScrolls();
+      }
+    });
+  }
+
+  function checkForAllScrolls() {
+    let _allOk = true;
+    $(document)
+      .find("[jHueLeftScrollified='true']")
+      .each((cnt, item) => {
+        if ($(item).is('body')) {
+          if ($(window).scrollLeft() > _this.options.threshold) {
+            _allOk = false;
+            $('#jHueScrollLeftAnchor').data('caller', $('body, html'));
+          }
+        } else if ($(item).scrollLeft() > _this.options.threshold) {
+          _allOk = false;
+          $('#jHueScrollLeftAnchor').data('caller', $(item));
+        }
+      });
+    if (_allOk) {
+      if (isActive) {
+        link.fadeOut(200, positionOtherAnchors);
+      }
+      $('#jHueScrollLeftAnchor').data('caller', null);
+    }
+  }
+
+  $(document).on('click', '#jHueScrollLeftAnchor', event => {
+    if ($('#jHueScrollLeftAnchor').data('caller') != null) {
+      $('#jHueScrollLeftAnchor')
+        .data('caller')
+        .animate({ scrollLeft: 0 }, 300, () => {
+          $(document)
+            .find("[jHueLeftScrollified='true']")
+            .trigger('scroll_update');
+          if (
+            $(document)
+              .find("[jHueLeftScrollified='true']")
+              .not($('#jHueScrollLeftAnchor').data('caller'))
+              .is('body') &&
+            $(window).scrollLeft() > _this.options.threshold
+          ) {
+            $('#jHueScrollLeftAnchor').data('caller', $('body, html'));
+          } else {
+            checkForAllScrolls();
+          }
+        });
+    }
+    return false;
+  });
+
+  huePubSub.subscribe('hue.scrollleft.show', () => {
+    isActive = true;
+  });
+
+  huePubSub.subscribe('hue.scrollleft.hide', () => {
+    isActive = false;
+    if (link.is(':visible')) {
+      link.hide();
+    }
+  });
+};
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+  });
+};
+
+$[pluginName] = function(options) {
+  new Plugin($('body'), options);
+};

+ 186 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.scrollup.js

@@ -0,0 +1,186 @@
+// 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.
+
+import $ from 'jquery';
+
+import huePubSub from 'utils/huePubSub';
+
+/*
+ * jHue scroll to top plugin
+ * Can be used globally with
+ *   $.jHueScrollUp()
+ * or with a target for the scroll up
+ *   $(element).jHueScrollUp()
+ *
+ *   options:
+ *    - threshold: (default 100) value in pixels, scroll amount before the link appears
+ */
+
+const pluginName = 'jHueScrollUp',
+  defaults = {
+    threshold: 100, // it displays it after 100 px of scroll
+    scrollLeft: false
+  };
+
+function Plugin(element, options) {
+  this.element = element;
+  this.options = $.extend({}, defaults, options);
+  this._defaults = defaults;
+  this._name = pluginName;
+  if ($(element).attr('jHueScrollified') !== 'true') {
+    this.setupScrollUp();
+  }
+  if (this.options.scrollLeft) {
+    $(element).jHueScrollLeft(this.options.threshold);
+  }
+}
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, defaults, options);
+};
+
+Plugin.prototype.setupScrollUp = function() {
+  const _this = this;
+  let link = null;
+
+  if ($('#jHueScrollUpAnchor').length > 0) {
+    // just one scroll up per page
+    link = $('#jHueScrollUpAnchor');
+    $(document).off('click', '#jHueScrollUpAnchor');
+  } else {
+    link = $('<a/>')
+      .attr('id', 'jHueScrollUpAnchor')
+      .addClass('hueAnchor hueAnchorScroller')
+      .attr('href', 'javascript:void(0)')
+      .html("<i class='fa fa-fw fa-chevron-up'></i>")
+      .appendTo(HUE_CONTAINER);
+  }
+
+  $(_this.element).attr('jHueScrollified', 'true');
+
+  if ($(_this.element).is('body')) {
+    setScrollBehavior($(window), $('body, html'));
+  } else {
+    setScrollBehavior($(_this.element), $(_this.element));
+  }
+
+  function positionOtherAnchors() {
+    const upPosition =
+      $('#jHueScrollUpAnchor')
+        .css('right')
+        .replace(/px/gi, '') * 1;
+    let right = upPosition - 30;
+    if ($('#jHueScrollUpAnchor').is(':visible')) {
+      right = upPosition;
+    }
+
+    if ($('#jHueScrollLeftAnchor').is(':visible')) {
+      $('#jHueScrollLeftAnchor').css('right', right + 50 + 'px');
+      right += 50;
+    }
+
+    $('.hue-datatable-search').css('right', right + 50 + 'px');
+  }
+
+  huePubSub.subscribe('reposition.scroll.anchor.up', () => {
+    $('#jHueScrollUpAnchor').css('right', '20px');
+    if (!$(_this.element).is('body') && $(_this.element).is(':visible')) {
+      const adjustRight =
+        $(window).width() - ($(_this.element).width() + $(_this.element).offset().left);
+      if (adjustRight > 0) {
+        $('#jHueScrollUpAnchor').css('right', adjustRight + 'px');
+      }
+    }
+    positionOtherAnchors();
+  });
+
+  function setScrollBehavior(scrolled, scrollable) {
+    scrolled.scroll(() => {
+      if (scrolled.scrollTop() > _this.options.threshold) {
+        if (link.is(':hidden')) {
+          huePubSub.publish('reposition.scroll.anchor.up');
+          link.fadeIn(200, () => {
+            huePubSub.publish('reposition.scroll.anchor.up');
+          });
+        }
+        if (
+          $(_this.element).data('lastScrollTop') == null ||
+          $(_this.element).data('lastScrollTop') < scrolled.scrollTop()
+        ) {
+          $('#jHueScrollUpAnchor').data('caller', scrollable);
+        }
+        $(_this.element).data('lastScrollTop', scrolled.scrollTop());
+      } else {
+        checkForAllScrolls();
+      }
+    });
+    window.setTimeout(() => {
+      huePubSub.publish('reposition.scroll.anchor.up');
+    }, 0);
+  }
+
+  function checkForAllScrolls() {
+    let _allOk = true;
+    $(document)
+      .find("[jHueScrollified='true']")
+      .each((cnt, item) => {
+        if ($(item).is('body')) {
+          if ($(window).scrollTop() > _this.options.threshold) {
+            _allOk = false;
+            $('#jHueScrollUpAnchor').data('caller', $('body, html'));
+          }
+        } else if ($(item).scrollTop() > _this.options.threshold) {
+          _allOk = false;
+          $('#jHueScrollUpAnchor').data('caller', $(item));
+        }
+      });
+    if (_allOk) {
+      link.fadeOut(200, positionOtherAnchors);
+      $('#jHueScrollUpAnchor').data('caller', null);
+    }
+  }
+
+  $(document).on('click', '#jHueScrollUpAnchor', event => {
+    if ($('#jHueScrollUpAnchor').data('caller') != null) {
+      $('#jHueScrollUpAnchor')
+        .data('caller')
+        .animate({ scrollTop: 0 }, 300, () => {
+          if (
+            $(document)
+              .find("[jHueScrollified='true']")
+              .not($('#jHueScrollUpAnchor').data('caller'))
+              .is('body') &&
+            $(window).scrollTop() > _this.options.threshold
+          ) {
+            $('#jHueScrollUpAnchor').data('caller', $('body, html'));
+          } else {
+            checkForAllScrolls();
+          }
+        });
+    }
+    return false;
+  });
+};
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+  });
+};
+
+$[pluginName] = function(options) {
+  new Plugin($('body'), options);
+};

+ 220 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.selector.js

@@ -0,0 +1,220 @@
+// 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.
+
+import $ from 'jquery';
+
+/*
+ * jHue selector plugin
+ * it tranforms a select multiple into a searchable/selectable alphabetical list
+ */
+
+const pluginName = 'jHueSelector',
+  defaults = {
+    selectAllLabel: 'Select all',
+    showSelectAll: true,
+    searchPlaceholder: 'Search',
+    noChoicesFound: 'No choices found for this element',
+    width: 300,
+    height: 200,
+    onChange: function() {}
+  };
+
+function Plugin(element, options) {
+  this.element = element;
+  this.options = $.extend({}, defaults, options);
+  this._defaults = defaults;
+  this._name = pluginName;
+  this.init();
+}
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, defaults, options);
+};
+
+Plugin.prototype.init = function() {
+  const _this = this;
+  const addressBook = [];
+  const selectorContainer = $('<div>');
+  if (this.options.width != 300) {
+    selectorContainer.width(this.options.width);
+  }
+  $(_this.element).hide();
+  $(_this.element)
+    .find('option')
+    .each((cnt, opt) => {
+      const initial = $(opt)
+        .text()
+        .substr(0, 1)
+        .toLowerCase();
+      if (addressBook[initial] == null) {
+        addressBook[initial] = [];
+      }
+      addressBook[initial].push($(opt));
+    });
+  const sortedKeys = [];
+  for (const key in addressBook) {
+    if (addressBook.hasOwnProperty(key)) {
+      sortedKeys.push(key);
+    }
+  }
+  sortedKeys.sort();
+
+  if (sortedKeys.length == 0) {
+    $(_this.element).after(
+      $('<div>')
+        .addClass('alert')
+        .css('margin-top', '-2px')
+        .css('float', 'left')
+        .html(this.options.noChoicesFound)
+    );
+  } else {
+    selectorContainer.addClass('jHueSelector');
+    const body = $('<div>').addClass('jHueSelectorBody');
+    body.appendTo(selectorContainer);
+
+    for (let i = 0; i < sortedKeys.length; i++) {
+      const key = sortedKeys[i];
+      const ul = $('<ul>');
+      const dividerLi = $('<li>').addClass('selectorDivider');
+      dividerLi.html('<strong>' + key.toUpperCase() + '</strong>');
+      dividerLi.appendTo(ul);
+      $.each(addressBook[key], (cnt, opt) => {
+        const li = $('<li>');
+        const lbl = $('<label>').text(opt.text());
+        const chk = $('<input>')
+          .attr('type', 'checkbox')
+          .addClass('selector')
+          .change(function() {
+            if ($(this).is(':checked')) {
+              $(this)
+                .data('opt')
+                .attr('selected', 'selected');
+            } else {
+              $(this)
+                .data('opt')
+                .removeAttr('selected');
+            }
+            _this.options.onChange();
+          })
+          .data('opt', opt)
+          .prependTo(lbl);
+        if (opt.is(':selected')) {
+          chk.attr('checked', 'checked');
+        }
+        lbl.appendTo(li);
+        li.appendTo(ul);
+      });
+      ul.appendTo(body);
+    }
+
+    const header = $('<div>').addClass('jHueSelectorHeader');
+    header.prependTo(selectorContainer);
+
+    const selectAll = $('<label>').html('&nbsp;');
+
+    if (this.options.showSelectAll) {
+      selectAll.text(this.options.selectAllLabel);
+      $('<input>')
+        .attr('type', 'checkbox')
+        .change(function() {
+          const isChecked = $(this).is(':checked');
+          selectorContainer.find('input.selector:visible').each(function() {
+            if (isChecked) {
+              $(this).prop('checked', true);
+              $(this)
+                .data('opt')
+                .attr('selected', 'selected');
+            } else {
+              $(this).prop('checked', false);
+              $(this)
+                .data('opt')
+                .removeAttr('selected');
+            }
+          });
+          if (searchBox.val() != '') {
+            $(this).prop('checked', false);
+          }
+          _this.options.onChange();
+        })
+        .prependTo(selectAll);
+    }
+
+    selectAll.appendTo(header);
+
+    const searchBox = $('<input>')
+      .attr('type', 'text')
+      .attr('placeholder', this.options.searchPlaceholder)
+      .keyup(function() {
+        body
+          .find('ul')
+          .attr('show', true)
+          .show();
+        const q = $.trim($(this).val());
+        if (q != '') {
+          body.find('li.selectorDivider').hide();
+          body.find('label').each(function() {
+            if (
+              $(this)
+                .text()
+                .toLowerCase()
+                .indexOf(q.toLowerCase()) > -1
+            ) {
+              $(this)
+                .parent()
+                .show();
+            } else {
+              $(this)
+                .parent()
+                .hide();
+            }
+          });
+          body.find('ul').attr('show', false);
+          body
+            .find('ul > *:visible')
+            .parent()
+            .attr('show', true)
+            .find('li.selectorDivider')
+            .show();
+        } else {
+          body.find('li.selectorDivider').show();
+          body
+            .find('label')
+            .parent()
+            .show();
+        }
+        body.find('ul[show=false]').hide();
+        body.find('ul[show=true]').show();
+      });
+    if (this.options.width != 300) {
+      searchBox.css('margin-left', this.options.width - 120 + 'px');
+    }
+    searchBox.prependTo(header);
+
+    body.height(this.options.height - header.outerHeight());
+
+    $(_this.element).after(selectorContainer);
+  }
+};
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    if (!$.data(this, 'plugin_' + pluginName)) {
+      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+    } else {
+      $.data(this, 'plugin_' + pluginName).setOptions(options);
+    }
+  });
+};

+ 724 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.tableextender.js

@@ -0,0 +1,724 @@
+// 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.
+
+import $ from 'jquery';
+
+import huePubSub from 'utils/huePubSub';
+
+/*
+ * jHue table extender plugin
+ *
+ */
+
+const pluginName = 'jHueTableExtender',
+  defaults = {
+    fixedHeader: false,
+    fixedFirstColumn: false,
+    fixedFirstColumnTopMargin: 0,
+    headerSorting: true,
+    lockSelectedRow: false,
+    firstColumnTooltip: false,
+    classToRemove: 'resultTable',
+    hintElement: null,
+    includeNavigator: true,
+    mainScrollable: window,
+    stickToTopPosition: -1,
+    app: null,
+    labels: {
+      GO_TO_COLUMN: 'Go to column:',
+      PLACEHOLDER: 'column name...',
+      LOCK: 'Click to lock row',
+      UNLOCK: 'Click to unlock row'
+    }
+  };
+
+function Plugin(element, options) {
+  this.element = element;
+  this.setOptions(options);
+  this._name = pluginName;
+  this.init();
+}
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, defaults, options);
+  this.options.labels = $.extend(
+    {},
+    defaults.labels,
+    HUE_I18n.jHueTableExtender,
+    options ? options.labels : {}
+  );
+  this._defaults = defaults;
+
+  if (this.options.fixedHeader) {
+    drawHeader(this);
+  }
+  if (this.options.fixedFirstColumn) {
+    drawFirstColumn(this);
+  }
+};
+
+Plugin.prototype.resetSource = function() {
+  const _this = this;
+  if (_this.options.includeNavigator) {
+    const source = [];
+    $(this.element)
+      .find('th')
+      .each(function() {
+        source.push($(this).text());
+      });
+
+    $('#jHueTableExtenderNavigator')
+      .find('input')
+      .data('typeahead').source = source;
+  }
+};
+
+Plugin.prototype.drawHeader = function(skipCreation) {
+  drawHeader(this, skipCreation);
+};
+
+Plugin.prototype.drawFirstColumn = function() {
+  drawFirstColumn(this);
+};
+
+Plugin.prototype.drawLockedRows = function(force) {
+  const _this = this;
+  const $pluginElement = $(_this.element);
+  if ($pluginElement.data('lockedRows')) {
+    const locks = $pluginElement.data('lockedRows');
+    Object.keys(locks).forEach(idx => {
+      drawLockedRow(_this, idx.substr(1), force);
+    });
+  }
+};
+
+Plugin.prototype.init = function() {
+  $.expr[':'].econtains = function(obj, index, meta, stack) {
+    return (
+      (obj.textContent || obj.innerText || $(obj).text() || '').toLowerCase() ==
+      meta[3].toLowerCase()
+    );
+  };
+
+  const _this = this;
+  if (_this.options.includeNavigator) {
+    const jHueTableExtenderNavigator = $('<div>').attr('id', 'jHueTableExtenderNavigator');
+    $('<a>')
+      .attr('href', '#')
+      .addClass('pull-right')
+      .html('&times;')
+      .click(function(e) {
+        e.preventDefault();
+        $(this)
+          .parent()
+          .hide();
+      })
+      .appendTo(jHueTableExtenderNavigator);
+    $('<label>')
+      .html(
+        _this.options.labels.GO_TO_COLUMN +
+          ' <input type="text" placeholder="' +
+          _this.options.labels.PLACEHOLDER +
+          '" />'
+      )
+      .appendTo(jHueTableExtenderNavigator);
+
+    jHueTableExtenderNavigator.appendTo(HUE_CONTAINER);
+
+    $(_this.element)
+      .find('tbody')
+      .click(event => {
+        if ($.trim(getSelection()) == '') {
+          window.setTimeout(() => {
+            $('.rowSelected').removeClass('rowSelected');
+            $('.columnSelected').removeClass('columnSelected');
+            $('.cellSelected').removeClass('cellSelected');
+            $(event.target.parentNode).addClass('rowSelected');
+            $(event.target.parentNode)
+              .find('td')
+              .addClass('rowSelected');
+            jHueTableExtenderNavigator
+              .css(
+                'left',
+                (event.pageX + jHueTableExtenderNavigator.width() > $(window).width() - 10
+                  ? event.pageX - jHueTableExtenderNavigator.width() - 10
+                  : event.pageX) + 'px'
+              )
+              .css('top', event.pageY + 10 + 'px')
+              .show();
+            jHueTableExtenderNavigator.find('input').focus();
+          }, 100);
+        }
+      });
+
+    const source = [];
+    $(_this.element)
+      .find('th')
+      .each(function() {
+        source.push($(this).text());
+      });
+
+    jHueTableExtenderNavigator.find('input').typeahead({
+      source: source,
+      updater: function(item) {
+        jHueTableExtenderNavigator.hide();
+        $(_this.element)
+          .find(
+            'tr td:nth-child(' +
+              ($(_this.element)
+                .find('th:econtains(' + item + ')')
+                .index() +
+                1) +
+              ')'
+          )
+          .addClass('columnSelected');
+        if (_this.options.firstColumnTooltip) {
+          $(_this.element)
+            .find(
+              'tr td:nth-child(' +
+                ($(_this.element)
+                  .find('th:econtains(' + item + ')')
+                  .index() +
+                  1) +
+                ')'
+            )
+            .each(function() {
+              $(this)
+                .attr('rel', 'tooltip')
+                .attr(
+                  'title',
+                  '#' +
+                    $(this)
+                      .parent()
+                      .find('td:first-child')
+                      .text()
+                )
+                .tooltip({
+                  placement: 'left'
+                });
+            });
+        }
+        $(_this.element)
+          .parent()
+          .animate(
+            {
+              scrollLeft:
+                $(_this.element)
+                  .find('th:econtains(' + item + ')')
+                  .position().left +
+                $(_this.element)
+                  .parent()
+                  .scrollLeft() -
+                $(_this.element)
+                  .parent()
+                  .offset().left -
+                30
+            },
+            300
+          );
+        $(_this.element)
+          .find(
+            'tr.rowSelected td:nth-child(' +
+              ($(_this.element)
+                .find('th:econtains(' + item + ')')
+                .index() +
+                1) +
+              ')'
+          )
+          .addClass('cellSelected');
+      }
+    });
+
+    $(_this.element)
+      .parent()
+      .bind('mouseleave', () => {
+        jHueTableExtenderNavigator.hide();
+      });
+
+    jHueTableExtenderNavigator.bind('mouseenter', e => {
+      jHueTableExtenderNavigator.show();
+    });
+  }
+
+  if (_this.options.hintElement != null) {
+    let showAlertTimeout = -1;
+    $(_this.element)
+      .find('tbody')
+      .mousemove(() => {
+        window.clearTimeout(showAlertTimeout);
+        if (
+          $(_this.options.hintElement).data('show') == null ||
+          $(_this.options.hintElement).data('show')
+        ) {
+          showAlertTimeout = window.setTimeout(() => {
+            $(_this.options.hintElement).fadeIn();
+          }, 1300);
+        }
+      });
+
+    $(_this.options.hintElement)
+      .find('.close')
+      .click(() => {
+        $(_this.options.hintElement).data('show', false);
+      });
+  }
+
+  if (_this.options.fixedHeader) {
+    drawHeader(_this);
+  }
+  if (_this.options.fixedFirstColumn) {
+    drawFirstColumn(_this);
+  }
+
+  $(document).on('click dblclick', '.dataTables_wrapper > table tbody tr', function() {
+    $(
+      '.dataTables_wrapper > .jHueTableExtenderClonedContainerColumn table tbody tr.selected'
+    ).removeClass('selected');
+    if ($(this).hasClass('selected')) {
+      $(this).removeClass('selected');
+    } else {
+      $('.dataTables_wrapper > table tbody tr.selected').removeClass('selected');
+      $(this).addClass('selected');
+      $(
+        '.dataTables_wrapper > .jHueTableExtenderClonedContainerColumn table tbody tr:eq(' +
+          $(this).index() +
+          ')'
+      ).addClass('selected');
+    }
+  });
+  $(document).on('dblclick', '.dataTables_wrapper > table tbody tr', function() {
+    if (huePubSub) {
+      huePubSub.publish('table.row.show.details', {
+        idx: $(this).index(),
+        table: $(this).parents('table')
+      });
+    }
+  });
+};
+
+function drawLockedRow(plugin, rowNo, force) {
+  const $pluginElement = $(plugin.element);
+  const lockedRows = $pluginElement.data('lockedRows') || {};
+  const $header = $('#' + $pluginElement.attr('id') + 'jHueTableExtenderClonedContainer');
+  const $headerCounter = $(
+    '#' + $pluginElement.attr('id') + 'jHueTableExtenderClonedContainerCell'
+  );
+  $header.addClass('locked');
+  $headerCounter.addClass('locked');
+
+  function unlock($el) {
+    $header
+      .find('tr td:first-child')
+      .filter(function() {
+        return $(this).text() === rowNo + '';
+      })
+      .closest('tr')
+      .remove();
+    delete lockedRows['r' + $el.text()];
+    $el.parent().remove();
+    if ($header.find('tbody tr').length == 0) {
+      $header.removeClass('locked');
+      $headerCounter.removeClass('locked');
+    }
+  }
+
+  if (Object.keys(lockedRows).indexOf('r' + rowNo) === -1 || force) {
+    if (force) {
+      unlock(lockedRows['r' + rowNo].cell.find('td'));
+    }
+    const $clone = $('<tr>');
+    let tHtml = '';
+    const aoColumns = $pluginElement.data('aoColumns');
+    $pluginElement.data('data')[rowNo - 1].forEach((col, idx) => {
+      tHtml +=
+        '<td ' +
+        (aoColumns && !aoColumns[idx].bVisible ? 'style="display: none"' : '') +
+        '>' +
+        col +
+        '</td>';
+    });
+    $clone.html(tHtml);
+    $clone.addClass('locked');
+    $clone.appendTo($header.find('tbody'));
+    $pluginElement.data('lockedRows', lockedRows);
+    const $newTr = $('<tr>');
+    $newTr
+      .addClass('locked')
+      .html(
+        '<td class="pointer unlockable" title="' +
+          plugin.options.labels.UNLOCK +
+          '"><i class="fa fa-unlock muted"></i>' +
+          rowNo +
+          '</td>'
+      )
+      .appendTo($headerCounter.find('tbody'));
+    $newTr.find('td').on('click', function() {
+      unlock($(this));
+    });
+    lockedRows['r' + rowNo] = {
+      row: $clone,
+      cell: $newTr
+    };
+  } else {
+    lockedRows['r' + rowNo].row.appendTo($header.find('tbody'));
+    lockedRows['r' + rowNo].cell.appendTo($headerCounter.find('tbody'));
+    lockedRows['r' + rowNo].cell.find('td').on('click', function() {
+      unlock($(this));
+    });
+  }
+}
+
+function drawFirstColumn(plugin) {
+  const $pluginElement = $(plugin.element);
+  if (!$pluginElement.attr('id') && plugin.options.parentId) {
+    $pluginElement.attr('id', 'eT' + plugin.options.parentId);
+  }
+
+  const mainScrollable = plugin.options.mainScrollable;
+  const originalTh = $(plugin.element).find('thead>tr th:eq(0)');
+  let topPosition;
+  if (plugin.options.clonedContainerPosition == 'absolute') {
+    topPosition = $pluginElement.parent().position().top - $(mainScrollable).scrollTop();
+  } else {
+    topPosition = $pluginElement.parent().offset().top - $(mainScrollable).scrollTop();
+  }
+
+  $('#' + $pluginElement.attr('id') + 'jHueTableExtenderClonedContainerCell').remove();
+  const clonedCell = $('<table>').attr('class', $(plugin.element).attr('class'));
+  clonedCell.removeClass(plugin.options.classToRemove);
+  clonedCell.css('margin-bottom', '0').css('table-layout', 'fixed');
+  const clonedCellTHead = $('<thead>');
+  clonedCellTHead.appendTo(clonedCell);
+  const clonedCellTH = originalTh.clone();
+  clonedCellTH.appendTo(clonedCellTHead);
+  clonedCellTH.width(originalTh.width()).css({
+    'background-color': '#FFFFFF',
+    'border-color': 'transparent'
+  });
+  clonedCellTH.click(() => {
+    originalTh.click();
+  });
+  $('<tbody>').appendTo(clonedCell);
+
+  const clonedCellContainer = $('<div>')
+    .css('background-color', '#FFFFFF')
+    .width(originalTh.outerWidth());
+
+  clonedCell.appendTo(clonedCellContainer);
+
+  const clonedCellVisibleContainer = $('<div>')
+    .attr('id', $(plugin.element).attr('id') + 'jHueTableExtenderClonedContainerCell')
+    .addClass('jHueTableExtenderClonedContainerCell')
+    .width(originalTh.outerWidth())
+    .css('overflow', 'hidden')
+    .css('top', topPosition + 'px');
+  clonedCellVisibleContainer.css('position', plugin.options.clonedContainerPosition || 'fixed');
+
+  clonedCellContainer.appendTo(clonedCellVisibleContainer);
+
+  $('#' + $pluginElement.attr('id') + 'jHueTableExtenderClonedContainerColumn').remove();
+  const clonedTable = $('<table>')
+    .attr('class', $(plugin.element).attr('class'))
+    .html('<thead></thead><tbody></tbody>');
+  clonedTable.removeClass(plugin.options.classToRemove);
+  clonedTable.css('margin-bottom', '0').css('table-layout', 'fixed');
+  $(plugin.element)
+    .find('thead>tr th:eq(0)')
+    .clone()
+    .appendTo(clonedTable.find('thead'));
+  const clonedTBody = clonedTable.find('tbody');
+  const clones = $(plugin.element)
+    .find('tbody>tr td:nth-child(1)')
+    .clone();
+  let h = '';
+  clones.each(function() {
+    h += '<tr><td>' + $(this).html() + '</td></tr>';
+  });
+  clonedTBody.html(h);
+  if (plugin.options.lockSelectedRow) {
+    clonedTBody.find('td').each(function() {
+      const cell = $(this);
+      cell
+        .attr('title', plugin.options.labels.LOCK)
+        .addClass('lockable pointer')
+        .on('click', function() {
+          drawLockedRow(plugin, $(this).text() * 1);
+        });
+      $('<i>')
+        .addClass('fa fa-lock muted')
+        .prependTo(cell);
+    });
+  }
+  clonedTable
+    .find('thead>tr th:eq(0)')
+    .width(originalTh.width())
+    .css('background-color', '#FFFFFF');
+
+  const clonedTableContainer = $('<div>')
+    .css('background-color', '#FFFFFF')
+    .width(originalTh.outerWidth())
+    .height($pluginElement.parent().get(0).scrollHeight);
+  clonedTable.appendTo(clonedTableContainer);
+
+  const clonedTableVisibleContainer = $('<div>')
+    .attr('id', $pluginElement.attr('id') + 'jHueTableExtenderClonedContainerColumn')
+    .addClass('jHueTableExtenderClonedContainerColumn')
+    .width(originalTh.outerWidth())
+    .height($pluginElement.parent().height())
+    .css('overflow', 'hidden')
+    .css('top', topPosition + 'px');
+  clonedTableVisibleContainer.css('position', plugin.options.clonedContainerPosition || 'fixed');
+
+  clonedTableContainer.appendTo(clonedTableVisibleContainer);
+  clonedTableVisibleContainer.appendTo($pluginElement.parent());
+
+  clonedCellVisibleContainer.appendTo($pluginElement.parent());
+
+  window.clearInterval($pluginElement.data('firstcol_interval'));
+  const firstColInt = window.setInterval(
+    () => {
+      if ($pluginElement.parent().height() != $pluginElement.parent().data('h')) {
+        clonedTableContainer.height($pluginElement.parent().get(0).scrollHeight);
+        clonedTableVisibleContainer.height($pluginElement.parent().height());
+        $pluginElement.parent().data('h', clonedTableVisibleContainer.height());
+      }
+    },
+    250,
+    plugin.options.app
+  );
+  $pluginElement.data('firstcol_interval', firstColInt);
+
+  $pluginElement.parent().resize(() => {
+    clonedTableContainer.height($pluginElement.parent().get(0).scrollHeight);
+    clonedTableVisibleContainer.height($pluginElement.parent().height());
+  });
+
+  $pluginElement.parent().scroll(() => {
+    clonedTableContainer.css(
+      'marginTop',
+      -$pluginElement.parent().scrollTop() + plugin.options.fixedFirstColumnTopMargin + 'px'
+    );
+  });
+
+  clonedTableContainer.css(
+    'marginTop',
+    -$pluginElement.parent().scrollTop() + plugin.options.fixedFirstColumnTopMargin + 'px'
+  );
+
+  function positionClones() {
+    let pos = plugin.options.stickToTopPosition;
+    if (typeof pos === 'function') {
+      pos = pos();
+    }
+    if (pos > -1) {
+      if ($pluginElement.offset().top < pos) {
+        clonedCellVisibleContainer.css('top', pos + 'px');
+      } else {
+        clonedCellVisibleContainer.css('top', $pluginElement.offset().top + 'px');
+      }
+      clonedTableVisibleContainer.css('top', $pluginElement.offset().top + 'px');
+    } else if (plugin.options.clonedContainerPosition == 'absolute') {
+      clonedTableVisibleContainer.css('top', $pluginElement.parent().position().top + 'px');
+      clonedCellVisibleContainer.css('top', $pluginElement.parent().position().top + 'px');
+    } else {
+      clonedTableVisibleContainer.css('top', $pluginElement.parent().offset().top + 'px');
+      clonedCellVisibleContainer.css('top', $pluginElement.parent().offset().top + 'px');
+    }
+  }
+
+  positionClones();
+
+  $(mainScrollable).on('scroll', positionClones);
+}
+
+function drawHeader(plugin, skipCreation) {
+  const $pluginElement = $(plugin.element);
+  if (!$pluginElement.attr('id') && plugin.options.parentId) {
+    $pluginElement.attr('id', 'eT' + plugin.options.parentId);
+  }
+
+  if (typeof skipCreation === 'undefined') {
+    const mainScrollable = plugin.options.mainScrollable;
+
+    $('#' + $pluginElement.attr('id') + 'jHueTableExtenderClonedContainer').remove();
+    const clonedTable = $('<table>').attr('class', $(plugin.element).attr('class'));
+    clonedTable.removeClass(plugin.options.classToRemove);
+    clonedTable.css('margin-bottom', '0').css('table-layout', 'fixed');
+    const clonedTableTHead = $('<thead>');
+    clonedTableTHead.appendTo(clonedTable);
+    const clonedTableTR = $pluginElement.find('thead>tr').clone();
+    clonedTableTR.appendTo(clonedTableTHead);
+    $('<tbody>').appendTo(clonedTable);
+
+    clonedTable.find('thead>tr th').wrapInner('<span></span>');
+
+    $pluginElement.find('thead>tr th').each(function(i) {
+      const originalTh = $(this);
+      originalTh.removeAttr('data-bind');
+      clonedTable
+        .find('thead>tr th:eq(' + i + ')')
+        .width(originalTh.width())
+        .css('background-color', '#FFFFFF')
+        .click(function() {
+          originalTh.click();
+          if (plugin.options.headerSorting) {
+            clonedTable.find('thead>tr th').attr('class', 'sorting');
+          }
+          $(this).attr('class', originalTh.attr('class'));
+        });
+    });
+
+    const clonedTableContainer = $('<div>').width($pluginElement.outerWidth());
+    clonedTable.appendTo(clonedTableContainer);
+
+    let topPosition;
+    if (plugin.options.clonedContainerPosition == 'absolute') {
+      topPosition = $pluginElement.parent().position().top - $(mainScrollable).scrollTop();
+    } else {
+      topPosition = $pluginElement.parent().offset().top - $(mainScrollable).scrollTop();
+    }
+    const clonedTableVisibleContainer = $('<div>')
+      .attr('id', $pluginElement.attr('id') + 'jHueTableExtenderClonedContainer')
+      .addClass('jHueTableExtenderClonedContainer')
+      .width($pluginElement.parent().width())
+      .css('overflow-x', 'hidden')
+      .css('top', topPosition + 'px');
+    clonedTableVisibleContainer.css('position', plugin.options.clonedContainerPosition || 'fixed');
+
+    clonedTableContainer.appendTo(clonedTableVisibleContainer);
+    clonedTableVisibleContainer.prependTo($pluginElement.parent());
+
+    const throttledHeaderPadding = () => {
+      const firstCellWidth = clonedTable.find('thead>tr th:eq(0)').outerWidth();
+      clonedTable.find('thead>tr th').each(function() {
+        const leftPosition = $(this).position().left - firstCellWidth;
+        if (leftPosition + $(this).outerWidth() > 0 && leftPosition < 0) {
+          if (
+            $(this)
+              .find('span')
+              .width() +
+              -leftPosition <
+            $(this).outerWidth() - 20
+          ) {
+            // 20 is the sorting css width
+            $(this)
+              .find('span')
+              .css('paddingLeft', -leftPosition);
+          }
+        } else {
+          $(this)
+            .find('span')
+            .css('paddingLeft', 0);
+        }
+      });
+    };
+
+    let scrollTimeout = -1;
+    $pluginElement.parent().scroll(function() {
+      const scrollLeft = $(this).scrollLeft();
+      clonedTableVisibleContainer.scrollLeft(scrollLeft);
+      window.clearTimeout(scrollTimeout);
+      scrollTimeout = window.setTimeout(throttledHeaderPadding, 200);
+    });
+
+    $pluginElement.bind('headerpadding', () => {
+      scrollTimeout = window.setTimeout(throttledHeaderPadding, 200);
+    });
+
+    clonedTableVisibleContainer.scrollLeft($pluginElement.parent().scrollLeft());
+
+    $pluginElement.parent().data('w', clonedTableVisibleContainer.width());
+
+    window.clearInterval($pluginElement.data('header_interval'));
+    const headerInt = window.setInterval(
+      () => {
+        if ($pluginElement.parent().width() != $pluginElement.parent().data('w')) {
+          clonedTableVisibleContainer.width($pluginElement.parent().width());
+          $pluginElement.parent().data('w', clonedTableVisibleContainer.width());
+          $pluginElement.find('thead>tr th').each(function(i) {
+            clonedTable
+              .find('thead>tr th:eq(' + i + ')')
+              .width($(this).width())
+              .css('background-color', '#FFFFFF');
+          });
+        }
+      },
+      250,
+      plugin.options.app
+    );
+    $pluginElement.data('header_interval', headerInt);
+
+    $pluginElement.parent().resize(function() {
+      clonedTableVisibleContainer.width($(this).width());
+    });
+
+    const positionClones = () => {
+      let pos = plugin.options.stickToTopPosition;
+      if (typeof pos === 'function') {
+        pos = pos();
+      }
+      if (pos > -1) {
+        if ($pluginElement.offset().top < pos) {
+          clonedTableVisibleContainer.css('top', pos + 'px');
+        } else {
+          clonedTableVisibleContainer.css('top', $pluginElement.offset().top + 'px');
+        }
+      } else if (plugin.options.clonedContainerPosition == 'absolute') {
+        clonedTableVisibleContainer.css('top', $pluginElement.parent().position().top + 'px');
+      } else {
+        clonedTableVisibleContainer.css('top', $pluginElement.parent().offset().top + 'px');
+      }
+    };
+
+    positionClones();
+
+    $(mainScrollable).on('scroll', positionClones);
+  } else {
+    $('#' + $pluginElement.attr('id') + 'jHueTableExtenderClonedContainer')
+      .children('div')
+      .width($pluginElement.outerWidth());
+    $pluginElement.find('thead>tr th').each(function(i) {
+      const originalTh = $(this);
+      $('#' + $pluginElement.attr('id') + 'jHueTableExtenderClonedContainer')
+        .find('thead>tr th:eq(' + i + ')')
+        .width(originalTh.width())
+        .attr('class', originalTh.attr('class'));
+    });
+  }
+}
+
+function getSelection() {
+  let t = '';
+  if (window.getSelection) {
+    t = window.getSelection();
+  } else if (document.getSelection) {
+    t = document.getSelection();
+  } else if (document.selection) {
+    t = document.selection.createRange().text;
+  }
+  return t.toString();
+}
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    if (!$.data(this, 'plugin_' + pluginName)) {
+      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+    } else {
+      $.data(this, 'plugin_' + pluginName).resetSource();
+      $.data(this, 'plugin_' + pluginName).setOptions(options);
+    }
+  });
+};

+ 584 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.tableextender2.js

@@ -0,0 +1,584 @@
+// 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.
+
+import $ from 'jquery';
+
+import huePubSub from 'utils/huePubSub';
+import hueUtils from 'utils/hueUtils';
+
+const PLUGIN_NAME = 'jHueTableExtender2';
+
+const DEFAULT_OPTIONS = {
+  fixedHeader: true,
+  fixedFirstColumn: true,
+  fixedFirstColumnTopMargin: 0,
+  headerSorting: true,
+  lockSelectedRow: true,
+  firstColumnTooltip: false,
+  classToRemove: 'resultTable',
+  hintElement: null,
+  mainScrollable: window,
+  app: null,
+  stickToTopPosition: -1,
+  labels: {
+    GO_TO_COLUMN: 'Go to column:',
+    PLACEHOLDER: 'column name...',
+    LOCK: 'Lock row',
+    UNLOCK: 'Unlock row',
+    ROW_DETAILS: 'Show row details'
+  }
+};
+
+function Plugin(element, options) {
+  const self = this;
+  self.disposeFunctions = [];
+
+  self.lockedRows = {};
+  self.setOptions(options); // Sets self.options
+
+  self.$element = $(element);
+  self.$parent = self.$element.parent();
+  self.$mainScrollable = $(self.options.mainScrollable);
+  self.lastHeaderWidth = 0;
+
+  self.drawHeader(); // Sets self.headerRowContainer, self.thMapping
+  self.drawFirstColumn(); // Sets self.firstColumnInner, self.firstColumnTopCell and self.firstColumn
+  self.drawLockedRows();
+
+  const manyColumns = self.thMapping.length > 20;
+
+  const sortAdjustment = self.options.noSort ? 10 : 20; // 20 is the sorting css width
+
+  let firstCellWidth, leftPosition, th, thi, leftPadding;
+  const throttledHeaderPadding = function() {
+    firstCellWidth = self.options.fixedFirstColumn ? self.firstColumnTopCell.outerWidth() : 0;
+    for (thi = 0; thi < self.thMapping.length; thi++) {
+      th = self.thMapping[thi];
+      if (!th.original.is(':visible')) {
+        continue;
+      }
+      leftPosition = th.clone.position().left - firstCellWidth;
+      if (leftPosition + th.clone.outerWidth() > 0 && leftPosition < 0) {
+        if (th.cloneSpan.width() - leftPosition < th.clone.outerWidth() - sortAdjustment) {
+          leftPadding = -leftPosition;
+        } else {
+          leftPadding = th.clone.outerWidth() - sortAdjustment - th.cloneSpan.width();
+        }
+        th.cloneSpan.css('paddingLeft', leftPadding);
+      } else {
+        th.cloneSpan.css('paddingLeft', 0);
+      }
+    }
+  };
+
+  let scrollTimeout = -1;
+  const headerScroll = function() {
+    self.headerRowContainer.scrollLeft(self.$parent.scrollLeft());
+    if (manyColumns) {
+      window.clearTimeout(scrollTimeout);
+      scrollTimeout = window.setTimeout(throttledHeaderPadding, 200);
+    } else {
+      throttledHeaderPadding();
+    }
+  };
+  self.$parent.on('scroll', headerScroll);
+  self.disposeFunctions.push(() => {
+    self.$parent.off('scroll', headerScroll);
+  });
+
+  self.$element.bind('headerpadding', () => {
+    window.clearTimeout(scrollTimeout);
+    scrollTimeout = window.setTimeout(throttledHeaderPadding, 200);
+  });
+  self.disposeFunctions.push(() => {
+    self.$element.unbind('headerpadding');
+  });
+
+  const redrawSubscription = huePubSub.subscribe('table.extender.redraw', parentId => {
+    if (parentId == self.options.parentId) {
+      self.redraw();
+    }
+  });
+  self.disposeFunctions.push(() => {
+    redrawSubscription.remove();
+  });
+
+  const hideSubscription = huePubSub.subscribe('table.extender.hide', parentId => {
+    if (parentId == self.options.parentId) {
+      self.headerRowContainer.hide();
+      self.firstColumnInner.hide();
+      self.firstColumnTopCell.hide();
+      self.firstColumn.hide();
+    }
+  });
+  self.disposeFunctions.push(() => {
+    hideSubscription.remove();
+  });
+
+  const adjustSizes = function() {
+    if (self.lastHeaderWidth !== self.$parent.width()) {
+      self.lastHeaderWidth = self.$parent.width();
+      self.headerRowContainer.width(self.lastHeaderWidth);
+    }
+    for (thi = 0; thi < self.thMapping.length; thi++) {
+      th = self.thMapping[thi];
+      if (!th.original.is(':visible')) {
+        continue;
+      }
+      if (th.clone.lastWidth !== th.original.width()) {
+        th.clone.lastWidth = th.original.width();
+        th.clone.width(th.clone.lastWidth);
+      }
+    }
+
+    if (self.headerRowContainer.scrollLeft() !== self.$parent.scrollLeft()) {
+      self.headerRowContainer.scrollLeft(self.$parent.scrollLeft());
+      throttledHeaderPadding();
+    }
+  };
+  adjustSizes();
+  const sizeInterval = window.setInterval(adjustSizes, 300, self.options.app);
+  self.disposeFunctions.push(() => {
+    window.clearInterval(sizeInterval);
+  });
+
+  const clickHandler = function() {
+    if ($(this).hasClass('selected')) {
+      self.$parent.find('.selected').removeClass('selected');
+    } else {
+      self.$parent.find('.selected').removeClass('selected');
+      $(this).addClass('selected');
+      self.$parent
+        .find('.fixed-first-column table tbody tr:eq(' + $(this).index() + ')')
+        .addClass('selected');
+    }
+  };
+
+  const overHandler = function() {
+    self.$parent
+      .find('.fixed-first-column table tbody tr:eq(' + $(this).index() + ') td')
+      .addClass('fixed-first-col-hover');
+  };
+
+  const outHandler = function() {
+    self.$parent.find('.fixed-first-column table tbody tr td').removeClass('fixed-first-col-hover');
+  };
+
+  self.$parent.children('table').on('click dblclick', 'tbody tr', clickHandler);
+  self.$parent.children('table').on('mouseover', 'tbody tr', overHandler);
+  self.$parent.children('table').on('mouseout', 'tbody tr', outHandler);
+  self.disposeFunctions.push(() => {
+    self.$parent.children('table').off('click dblclick', 'tbody tr', clickHandler);
+    self.$parent.children('table').on('mouseover', 'tbody tr', overHandler);
+    self.$parent.children('table').on('mouseout', 'tbody tr', outHandler);
+  });
+
+  if (!self.options.disableTopPosition) {
+    self.repositionHeader();
+    const scrollFunction = self.repositionHeader.bind(self);
+    self.$mainScrollable.on('scroll', scrollFunction);
+    self.disposeFunctions.push(() => {
+      self.$mainScrollable.off('scroll', scrollFunction);
+    });
+  }
+}
+
+Plugin.prototype.redraw = function() {
+  const self = this;
+  self.drawHeader();
+  self.drawFirstColumn();
+  self.drawLockedRows(true);
+  self.repositionHeader();
+  window.setTimeout(() => {
+    self.headerRowContainer.scrollLeft(self.$parent.scrollLeft());
+    self.$element.trigger('headerpadding');
+  }, 300);
+};
+
+Plugin.prototype.destroy = function() {
+  const self = this;
+  self.disposeFunctions.forEach(disposeFunction => {
+    disposeFunction();
+  });
+};
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, DEFAULT_OPTIONS, options);
+  this.options.labels = $.extend(
+    {},
+    DEFAULT_OPTIONS.labels,
+    HUE_I18n.jHueTableExtender,
+    options ? options.labels : {}
+  );
+};
+
+Plugin.prototype.repositionHeader = function() {
+  const self = this;
+  if (self.options.disableTopPosition) {
+    return;
+  }
+  let pos = self.options.stickToTopPosition;
+  let topPos = 0;
+  let firstColTopPos = 0;
+  if (typeof pos === 'function') {
+    pos = pos();
+  }
+  if (window.IS_EMBEDDED) {
+    pos = $('.hue-embedded-container').offset().top;
+  }
+  let isFixed = false;
+  if (pos > -1) {
+    if (self.$element.offset().top < pos) {
+      topPos = pos;
+      isFixed = true;
+    } else {
+      topPos = self.$element.offset().top;
+      isFixed = false;
+    }
+    firstColTopPos = self.$element.offset().top;
+  } else if (self.options.clonedContainerPosition == 'absolute') {
+    topPos = self.$parent.position().top;
+    firstColTopPos = topPos;
+  } else {
+    topPos = self.$parent.offset().top;
+    firstColTopPos = topPos;
+  }
+
+  if (pos > -1) {
+    let fixCSS = {
+      top: '',
+      left: self.$parent.position().left + 'px',
+      position: 'absolute'
+    };
+    self.firstColumn.css(fixCSS);
+    if (isFixed) {
+      fixCSS = {
+        top: topPos + 'px',
+        left: '',
+        position: 'fixed'
+      };
+    }
+    self.firstColumnTopCell.css(fixCSS);
+    self.headerRowContainer.css(fixCSS);
+  } else {
+    self.firstColumn.scrollTop(self.$mainScrollable.scrollTop());
+    self.firstColumn.css('top', firstColTopPos + 'px');
+    self.headerRowContainer.css('top', topPos + 'px');
+    self.firstColumnTopCell.css('top', topPos + 'px');
+  }
+};
+
+Plugin.prototype.drawHeader = function() {
+  const self = this;
+  if (!self.$element.attr('id') && self.options.parentId) {
+    self.$element.attr('id', 'eT' + self.options.parentId);
+  }
+
+  $('#' + self.$element.attr('id') + 'jHueTableExtenderClonedContainer').remove();
+  const clonedTable = $('<table>').attr('class', self.$element.attr('class'));
+  clonedTable.removeClass(self.options.classToRemove);
+  clonedTable.css('margin-bottom', '0').css('table-layout', 'fixed');
+  const clonedTableTHead = $('<thead>');
+  clonedTableTHead.appendTo(clonedTable);
+  const clonedTableTR = self.$element.find('thead>tr').clone();
+  clonedTableTR.appendTo(clonedTableTHead);
+  $('<tbody>').appendTo(clonedTable);
+
+  const clonedThs = clonedTable.find('thead>tr th');
+  clonedThs.wrapInner('<span></span>');
+
+  if (typeof self.$element.data('updateThWidthsInterval') !== 'undefined') {
+    window.clearInterval(self.$element.data('updateThWidthsInterval'));
+  }
+
+  self.thMapping = [];
+  let totalThWidth = 0;
+  self.$element.find('thead>tr th').each(function(i) {
+    const originalTh = $(this);
+    originalTh.removeAttr('data-bind');
+    const clonedTh = $(clonedThs[i]).css('background-color', '#FFFFFF');
+    clonedTh.click(function() {
+      originalTh.click();
+      if (self.options.headerSorting) {
+        clonedThs.attr('class', 'sorting');
+      }
+      $(this).attr('class', originalTh.attr('class'));
+    });
+    clonedTh.width(originalTh.width());
+    totalThWidth += originalTh.width();
+    self.thMapping.push({
+      original: originalTh,
+      clone: clonedTh,
+      cloneSpan: clonedTh.children().first()
+    });
+  });
+
+  const headerRowDiv = $('<div>');
+  clonedTable.appendTo(headerRowDiv);
+
+  let topPosition;
+  if (self.options.clonedContainerPosition == 'absolute') {
+    topPosition = self.$parent.position().top - self.$mainScrollable.scrollTop();
+  } else {
+    topPosition = self.$parent.offset().top - self.$mainScrollable.scrollTop();
+  }
+  const headerRowContainer = $('<div>')
+    .attr('id', self.$element.attr('id') + 'jHueTableExtenderClonedContainer')
+    .addClass('fixed-header-row')
+    .width(totalThWidth)
+    .css('overflow-x', 'hidden');
+  if (!self.options.disableTopPosition) {
+    headerRowContainer.css('top', topPosition + 'px');
+  }
+  headerRowContainer.css('position', self.options.clonedContainerPosition || 'fixed');
+  self.lastHeaderWidth = self.$parent.width();
+  headerRowContainer.width(self.lastHeaderWidth);
+
+  headerRowDiv.appendTo(headerRowContainer);
+  headerRowContainer.prependTo(self.$parent);
+
+  headerRowContainer.scrollLeft(self.$parent.scrollLeft());
+
+  self.headerRowContainer = headerRowContainer;
+  self.$mainScrollable.trigger('scroll');
+};
+
+Plugin.prototype.drawFirstColumn = function(repositionHeader) {
+  const self = this;
+  if (!self.options.fixedFirstColumn) {
+    self.firstColumnInner = $();
+    self.firstColumnTopCell = $();
+    self.firstColumn = $();
+    return;
+  }
+  if (!self.$element.attr('id') && self.options.parentId) {
+    self.$element.attr('id', 'eT' + self.options.parentId);
+  }
+
+  const originalTh = self.$element.find('thead>tr th:eq(0)');
+  let topPosition;
+  if (self.options.clonedContainerPosition == 'absolute') {
+    topPosition = self.$parent.position().top - self.$mainScrollable.scrollTop();
+  } else {
+    topPosition = self.$parent.offset().top - self.$mainScrollable.scrollTop();
+  }
+
+  $('#' + self.$element.attr('id') + 'jHueTableExtenderClonedContainerCell').remove();
+  const clonedCell = $('<table>').attr('class', self.$element.attr('class'));
+  clonedCell.removeClass(self.options.classToRemove);
+  clonedCell.css('margin-bottom', '0').css('table-layout', 'fixed');
+  const clonedCellTHead = $('<thead><tr></tr></thead>');
+  clonedCellTHead.appendTo(clonedCell);
+  const clonedCellTH = originalTh.clone();
+  clonedCellTH.appendTo(clonedCellTHead.find('tr'));
+  clonedCellTH.width(originalTh.width()).css({
+    'background-color': '#FFFFFF',
+    'border-color': 'transparent'
+  });
+  clonedCellTH.click(() => {
+    originalTh.click();
+  });
+  $('<tbody>').appendTo(clonedCell);
+
+  const clonedCellContainer = $('<div>')
+    .css('background-color', '#FFFFFF')
+    .width(originalTh.outerWidth());
+
+  clonedCell.appendTo(clonedCellContainer);
+
+  const firstColumnTopCell = $('<div>')
+    .attr('id', self.$element.attr('id') + 'jHueTableExtenderClonedContainerCell')
+    .addClass('fixed-first-cell')
+    .width(originalTh.outerWidth())
+    .css('overflow', 'hidden')
+    .css('top', topPosition + 'px');
+  firstColumnTopCell.css('position', self.options.clonedContainerPosition || 'fixed');
+
+  clonedCellContainer.appendTo(firstColumnTopCell);
+
+  $('#' + self.$element.attr('id') + 'jHueTableExtenderClonedContainerColumn').remove();
+  const clonedTable = $('<table>')
+    .attr('class', self.$element.attr('class'))
+    .html('<thead><tr></tr></thead><tbody></tbody>');
+  clonedTable.removeClass(self.options.classToRemove);
+  clonedTable.css('margin-bottom', '0').css('table-layout', 'fixed');
+  self.$element
+    .find('thead>tr th:eq(0)')
+    .clone()
+    .appendTo(clonedTable.find('thead tr'));
+  const clonedTBody = clonedTable.find('tbody');
+  const clones = self.$element.find('tbody>tr td:nth-child(1)').clone();
+  let h = '';
+  let foundEmptyTh = false;
+  clones.each(function() {
+    if ($(this).html() === '') {
+      foundEmptyTh = true;
+    }
+    h += '<tr><td>' + $(this).html() + '</td></tr>';
+  });
+  if (foundEmptyTh) {
+    // In IE it's sometimes empty so we'll redraw in a bit
+    window.setTimeout(self.drawFirstColumn.bind(self), 200);
+    self.firstColumnInner = $();
+    self.firstColumnTopCell = $();
+    self.firstColumn = $();
+    return;
+  }
+  clonedTBody.html(h);
+  if (self.options.lockSelectedRow) {
+    clonedTBody.find('td').each(function(idx) {
+      const cell = $(this);
+      cell.addClass('lockable');
+      $('<i>')
+        .addClass('fa fa-lock pointer muted')
+        .prependTo(cell)
+        .on('click', function() {
+          self.drawLockedRow(
+            $(this)
+              .parent()
+              .text() * 1
+          );
+        })
+        .attr('title', self.options.labels.LOCK);
+      $('<i>')
+        .addClass('fa fa-expand pointer muted')
+        .prependTo(cell)
+        .on('click', () => {
+          huePubSub.publish('table.row.show.details', { idx: idx, table: self.$element });
+        })
+        .attr('title', self.options.labels.ROW_DETAILS);
+    });
+  }
+  clonedTable
+    .find('thead>tr th:eq(0)')
+    .width(originalTh.width())
+    .css('background-color', '#FFFFFF');
+
+  const firstColumnInner = $('<div>')
+    .css('background-color', '#FFFFFF')
+    .width(originalTh.outerWidth())
+    .height(self.$parent.get(0).scrollHeight);
+  clonedTable.appendTo(firstColumnInner);
+
+  const firstColumn = $('<div>')
+    .attr('id', self.$element.attr('id') + 'jHueTableExtenderClonedContainerColumn')
+    .addClass('fixed-first-column')
+    .width(originalTh.outerWidth())
+    .height(self.$parent.height())
+    .css('overflow', 'hidden')
+    .css('top', topPosition + 'px');
+  firstColumn.css('position', self.options.clonedContainerPosition || 'fixed');
+
+  firstColumnInner.appendTo(firstColumn);
+  firstColumn.insertAfter(self.$element.prev());
+
+  firstColumnTopCell.insertAfter(firstColumn);
+
+  self.firstColumnInner = firstColumnInner;
+  self.firstColumnTopCell = firstColumnTopCell;
+  self.firstColumn = firstColumn;
+
+  if (repositionHeader) {
+    self.repositionHeader();
+  }
+};
+
+Plugin.prototype.drawLockedRows = function(force) {
+  const self = this;
+  if (Object.keys(self.lockedRows).length === 0) {
+    self.headerRowContainer.find('tbody').empty();
+    self.headerRowContainer.removeClass('locked');
+    self.firstColumnTopCell.removeClass('locked');
+  } else {
+    self.headerRowContainer.addClass('locked');
+    self.firstColumnTopCell.addClass('locked');
+    Object.keys(self.lockedRows).forEach(idx => {
+      self.drawLockedRow(idx.substr(1), force);
+    });
+  }
+};
+
+Plugin.prototype.drawLockedRow = function(rowNo, force) {
+  const self = this;
+
+  function unlock($el) {
+    self.headerRowContainer
+      .find('tr td:first-child')
+      .filter(function() {
+        return $(this).text() === rowNo + '';
+      })
+      .closest('tr')
+      .remove();
+    delete self.lockedRows['r' + $el.text()];
+    $el.parent().remove();
+    if (self.headerRowContainer.find('tbody tr').length == 0) {
+      self.headerRowContainer.removeClass('locked');
+      self.firstColumnTopCell.removeClass('locked');
+    }
+  }
+
+  if (Object.keys(self.lockedRows).indexOf('r' + rowNo) === -1 || force) {
+    if (force) {
+      unlock(self.lockedRows['r' + rowNo].cell.find('td'));
+    }
+    const $clone = $('<tr>').addClass('locked');
+    let tHtml = '';
+    const aoColumns = self.$element.data('aoColumns');
+    self.$element.data('data')[rowNo - 1].forEach((col, idx) => {
+      tHtml +=
+        '<td ' +
+        (aoColumns && !aoColumns[idx].bVisible ? 'style="display: none"' : '') +
+        '>' +
+        hueUtils.deXSS(col) +
+        '</td>';
+    });
+    $clone.html(tHtml);
+    $clone.appendTo(self.headerRowContainer.find('tbody'));
+    const $newTr = $('<tr>');
+    $newTr
+      .addClass('locked')
+      .html(
+        '<td class="pointer unlockable" title="' +
+          self.options.labels.UNLOCK +
+          '"><i class="fa fa-unlock muted"></i>' +
+          rowNo +
+          '</td>'
+      )
+      .appendTo(self.firstColumnTopCell.find('tbody'));
+    $newTr.find('td').on('click', function() {
+      unlock($(this));
+    });
+    self.lockedRows['r' + rowNo] = {
+      row: $clone,
+      cell: $newTr
+    };
+  } else {
+    self.lockedRows['r' + rowNo].row.appendTo(self.headerRowContainer.find('tbody'));
+    self.lockedRows['r' + rowNo].cell.appendTo(self.firstColumnTopCell.find('tbody'));
+    self.lockedRows['r' + rowNo].cell.find('td').on('click', function() {
+      unlock($(this));
+    });
+  }
+};
+
+$.fn[PLUGIN_NAME] = function(options) {
+  return this.each(function() {
+    if ($.data(this, 'plugin_' + PLUGIN_NAME)) {
+      $.data(this, 'plugin_' + PLUGIN_NAME).destroy();
+    }
+    $.data(this, 'plugin_' + PLUGIN_NAME, new Plugin(this, options));
+  });
+};

+ 153 - 0
desktop/core/src/desktop/js/jquery/plugins/jquery.tablescroller.js

@@ -0,0 +1,153 @@
+// 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.
+
+import $ from 'jquery';
+
+/*
+ * jHue table scroller plugin
+ *
+ * Three data attributes can be set on the table to modify the default behavior of the plugin:
+ * - data-tablescroller-min-height="N" where N is a value in pixels: specifies a minimum height for the scrolling table,
+ *      overriding the default 500px set by the plugin
+ * - data-tablescroller-min-height-disable="true": disable enforcing a minimum height for the table
+ * - data-tablescroller-disable="true": disable the plugin for the specific table
+ * - data-tablescroller-enforce-height="true": displays the table at its maximum height accordingly to the page
+ */
+
+const pluginName = 'jHueTableScroller',
+  defaults = {
+    minHeight: 300,
+    maxHeight: -1,
+    heightAfterCorrection: 40
+  };
+
+function Plugin(element, options) {
+  this.element = element;
+  this.options = $.extend({}, defaults, options);
+  this._defaults = defaults;
+  this._name = pluginName;
+  this.init();
+}
+
+Plugin.prototype.setOptions = function(options) {
+  this.options = $.extend({}, defaults, options);
+  resizeScrollingTable(this);
+};
+
+Plugin.prototype.init = function() {
+  const _this = this;
+
+  $(_this.element).data('original-height', $(_this.element).height());
+
+  const disableScrollingTable = $(_this.element)
+    .find('table')
+    .eq(0)
+    .data('tablescroller-disable');
+  if (disableScrollingTable == null || disableScrollingTable !== true) {
+    resizeScrollingTable(_this);
+    let _resizeTimeout = -1;
+    $(window).resize(() => {
+      window.clearTimeout(_resizeTimeout);
+      _resizeTimeout = window.setTimeout(() => {
+        resizeScrollingTable(_this);
+      }, 400);
+    });
+  }
+};
+
+function resizeScrollingTable(_this) {
+  const el = _this.element;
+  $(el)
+    .css('overflow-y', '')
+    .css('height', '');
+  $(el).css('overflow-x', 'auto');
+  let heightAfter = _this.options.heightAfterCorrection;
+  $(el)
+    .nextAll(':visible')
+    .each(function() {
+      heightAfter += $(this).outerHeight(true);
+    });
+
+  let heightCondition = $(el).height() > $(window).height() - $(el).offset().top - heightAfter;
+  const enforceHeight = $(_this.element)
+    .find('table')
+    .eq(0)
+    .data('tablescroller-enforce-height');
+  if (enforceHeight !== undefined && enforceHeight == true) {
+    heightCondition = true;
+  }
+
+  const fixedHeight =
+    $(_this.element)
+      .find('table')
+      .eq(0)
+      .data('tablescroller-fixed-height') || _this.options.maxHeight;
+
+  if (heightCondition) {
+    const specificMinHeight = $(el)
+      .find('table')
+      .eq(0)
+      .data('tablescroller-min-height');
+    let minHeightVal = _this.options.minHeight;
+    if (!isNaN(parseFloat(specificMinHeight)) && isFinite(specificMinHeight)) {
+      minHeightVal = parseFloat(specificMinHeight);
+    }
+    const disableMinHeight = $(_this.element)
+      .find('table')
+      .eq(0)
+      .data('tablescroller-min-height-disable');
+    if (disableMinHeight != null && disableMinHeight == true) {
+      if (heightCondition) {
+        $(el)
+          .css('overflow-y', 'auto')
+          .height(
+            fixedHeight > -1 ? fixedHeight : $(window).height() - $(el).offset().top - heightAfter
+          );
+      }
+    } else if ($(window).height() - $(el).offset().top - heightAfter > minHeightVal) {
+      $(el)
+        .css('overflow-y', 'auto')
+        .height(
+          fixedHeight > -1 ? fixedHeight : $(window).height() - $(el).offset().top - heightAfter
+        );
+    } else {
+      if ($(el).data('original-height') > minHeightVal) {
+        $(el)
+          .css('overflow-y', 'auto')
+          .height(minHeightVal);
+      }
+      if (fixedHeight > -1) {
+        $(el)
+          .css('overflow-y', 'auto')
+          .css('maxHeight', fixedHeight);
+      }
+    }
+  } else if (fixedHeight > -1) {
+    $(el)
+      .css('overflow-y', 'auto')
+      .css('maxHeight', fixedHeight);
+  }
+}
+
+$.fn[pluginName] = function(options) {
+  return this.each(function() {
+    if (!$.data(this, 'plugin_' + pluginName)) {
+      $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
+    } else {
+      $.data(this, 'plugin_' + pluginName).setOptions(options);
+    }
+  });
+};

+ 21 - 20
desktop/core/src/desktop/js/ext/jquery/hue.jquery.titleupdater.js → desktop/core/src/desktop/js/jquery/plugins/jquery.titleupdater.js

@@ -13,14 +13,17 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
+
+import $ from 'jquery';
+
 /*
  * jHue title updater plugin
  *
  */
 
-var pluginName = "jHueTitleUpdater",
+const pluginName = 'jHueTitleUpdater',
   defaults = {
-    message: "",
+    message: '',
     reset: false
   };
 
@@ -31,31 +34,29 @@ function Plugin(options) {
   this.updateStatusBar();
 }
 
-Plugin.prototype.setOptions = function (options) {
+Plugin.prototype.setOptions = function(options) {
   this.options = $.extend({}, defaults, options);
 };
 
-Plugin.prototype.updateStatusBar = function () {
-  var _this = this;
-  if (_this.options.reset && $(document).data("jHueTitleUpdaterOriginal") != null) {
-    document.title = $(document).data("jHueTitleUpdaterOriginal");
-    $(document).data("jHueTitleUpdaterOriginal", null);
-  }
-  else if (_this.options.message != "") {
-    if ($(document).data("jHueTitleUpdaterOriginal") == null) {
-      $(document).data("jHueTitleUpdaterOriginal", document.title);
+Plugin.prototype.updateStatusBar = function() {
+  const _this = this;
+  if (_this.options.reset && $(document).data('jHueTitleUpdaterOriginal') != null) {
+    document.title = $(document).data('jHueTitleUpdaterOriginal');
+    $(document).data('jHueTitleUpdaterOriginal', null);
+  } else if (_this.options.message != '') {
+    if ($(document).data('jHueTitleUpdaterOriginal') == null) {
+      $(document).data('jHueTitleUpdaterOriginal', document.title);
     }
-    document.title = _this.options.message + " - " + $(document).data("jHueTitleUpdaterOriginal");
+    document.title = _this.options.message + ' - ' + $(document).data('jHueTitleUpdaterOriginal');
   }
 };
 
-$[pluginName] = function () {
-};
+$[pluginName] = function() {};
 
-$[pluginName].reset = function () {
-  new Plugin({ reset: true});
+$[pluginName].reset = function() {
+  new Plugin({ reset: true });
 };
 
-$[pluginName].set = function (message) {
-  new Plugin({ message: message});
-};
+$[pluginName].set = function(message) {
+  new Plugin({ message: message });
+};

+ 1 - 0
desktop/core/src/desktop/js/ko/bindings/ko.dropzone.js

@@ -14,6 +14,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+import Dropzone from 'dropzone';
 import $ from 'jquery';
 import ko from 'knockout';
 

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

@@ -16,8 +16,7 @@
 
 import $ from 'jquery';
 import ko from 'knockout';
-
-// TODO: Depends on MediumEditor
+import MediumEditor from 'medium-editor';
 
 ko.bindingHandlers.medium = {
   init: function(element, valueAccessor, allBindings) {

Fișier diff suprimat deoarece este prea mare
+ 0 - 0
desktop/core/src/desktop/static/desktop/ext/js/dropzone.min.js


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
desktop/core/src/desktop/static/desktop/ext/js/medium-editor.min.js


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-c56027ed5fcc7f4abc0b.js


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-c56027ed5fcc7f4abc0b.js.map


Fișier diff suprimat deoarece este prea mare
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-cd1cd1feafc6ddb99531.js.map


+ 1 - 1
desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-cd1cd1feafc6ddb99531.js → desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js

@@ -37,4 +37,4 @@
   !*** multi ./desktop/core/src/desktop/js/sql/sqlSyntaxWebWorker.js ***!
   \*********************************************************************/
 /*! no static exports found */function(e,t,a){e.exports=a(/*! ./desktop/core/src/desktop/js/sql/sqlSyntaxWebWorker.js */"./desktop/core/src/desktop/js/sql/sqlSyntaxWebWorker.js")}});
-//# sourceMappingURL=sqlSyntaxWebWorker-bundle-cd1cd1feafc6ddb99531.js.map
+//# sourceMappingURL=sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js.map

Fișier diff suprimat deoarece este prea mare
+ 0 - 0
desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js.map


+ 0 - 337
desktop/core/src/desktop/static/desktop/js/jquery.hdfsautocomplete.js

@@ -1,337 +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.
-/*
- * jHue HDFS autocomplete plugin
- * augment a textbox into an HDFS autocomplete
- */
-
-(function ($, window, document, undefined) {
-  var pluginName = "jHueHdfsAutocomplete",
-      defaults = {
-        home: "/",
-        onEnter: function () {
-        },
-        onBlur: function () {
-        },
-        onPathChange: function () {
-        },
-        smartTooltip: "",
-        smartTooltipThreshold: 10, // needs 10 up/down or click actions and no tab to activate the smart tooltip
-        showOnFocus: false,
-        skipKeydownEvents: false,
-        skipEnter: false,
-        skipScrollEvent: false,
-        zIndex: 33000,
-        root: "/",
-        isS3: false
-      };
-
-  function Plugin(element, options) {
-    this.element = element;
-    this.options = $.extend({}, defaults, options);
-    this._defaults = defaults;
-    this._name = pluginName;
-    this.init();
-  }
-
-  Plugin.prototype.init = function () {
-
-    var _this = this;
-    var _el = $(_this.element);
-    _el.addClass("jHueAutocompleteElement");
-    _el.attr("autocomplete", "off"); // prevents default browser behavior
-
-    // creates autocomplete popover
-    if ($("#jHueHdfsAutocomplete").length == 0) {
-      $("<div>").attr("id", "jHueHdfsAutocomplete").addClass("jHueAutocomplete popover")
-          .attr("style", "position:absolute;display:none;max-width:1000px;z-index:" + _this.options.zIndex)
-          .html('<div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p><ul class="unstyled"></ul></p></div></div>')
-          .appendTo($(HUE_CONTAINER));
-    }
-
-    function setHueBreadcrumbCaretAtEnd(element) {
-      var elemLength = element.value.length;
-      if (document.selection) {
-        element.focus();
-        var _oSel = document.selection.createRange();
-        _oSel.moveStart('character', -elemLength);
-        _oSel.moveStart('character', elemLength);
-        _oSel.moveEnd('character', 0);
-        _oSel.select();
-      }
-      else if (element.selectionStart || element.selectionStart == '0') {
-        element.selectionStart = elemLength;
-        element.selectionEnd = elemLength;
-        element.focus();
-      }
-    }
-
-
-    _el.focus(function () {
-      $(document.body).on("contextmenu", function (e) {
-        e.preventDefault(); // prevents native menu on FF for Mac from being shown
-      });
-      setHueBreadcrumbCaretAtEnd(_this.element);
-    });
-
-    _el.keydown(function (e) {
-      if (e.keyCode == 9) {
-        e.preventDefault();
-        showHdfsAutocomplete(function () {
-          var path = _el.val();
-          if (path.indexOf("/") > -1) {
-            path = path.substr(path.lastIndexOf("/") + 1);
-          }
-          guessHdfsPath(path);
-        });
-      }
-    });
-
-    function smartTooltipMaker() {
-      if (_this.options.smartTooltip != "" && typeof $.totalStorage != "undefined" && $.totalStorage("jHueHdfsAutocompleteTooltip") != -1) {
-        var cnt = 0;
-        if ($.totalStorage("jHueHdfsAutocompleteTooltip") != null) {
-          cnt = $.totalStorage("jHueHdfsAutocompleteTooltip") + 1;
-        }
-        $.totalStorage("jHueHdfsAutocompleteTooltip", cnt);
-        if (cnt >= _this.options.smartTooltipThreshold) {
-          _el.tooltip({
-            animation: true,
-            title: _this.options.smartTooltip,
-            trigger: "manual",
-            placement: "top"
-          }).tooltip("show");
-          window.setTimeout(function () {
-            _el.tooltip("hide");
-          }, 10000);
-          $.totalStorage("jHueHdfsAutocompleteTooltip", -1);
-        }
-      }
-    }
-
-    if (! _this.options.skipScrollEvent){
-      $(window).on("scroll", function(){
-        $("#jHueHdfsAutocomplete").css("top", _el.offset().top + _el.outerHeight() - 1).css("left", _el.offset().left).width(_el.outerWidth() - 4);
-      });
-    }
-
-
-    _el.on("keydown", function (e) {
-      if (!_this.options.skipKeydownEvents && e.keyCode == 191) {
-        e.preventDefault();
-      }
-      if (e.keyCode == 32 && e.ctrlKey) {
-        e.preventDefault();
-      }
-      if (_this.options.skipEnter && e.keyCode === 13){
-        e.preventDefault();
-        e.stopPropagation();
-        e.stopImmediatePropagation();
-      }
-    });
-
-
-    var _hdfsAutocompleteSelectedIndex = -1;
-    var _filterTimeout = -1;
-    _el.keyup(function (e) {
-      window.clearTimeout(_filterTimeout);
-      if ($.inArray(e.keyCode, [38, 40, 13, 32, 191]) == -1) {
-        _hdfsAutocompleteSelectedIndex = -1;
-        _filterTimeout = window.setTimeout(function () {
-          var path = _el.val();
-          if (path.indexOf("/") > -1) {
-            path = path.substr(path.lastIndexOf("/") + 1);
-          }
-          $("#jHueHdfsAutocomplete ul li").show();
-          $("#jHueHdfsAutocomplete ul li").each(function () {
-            if ($(this).text().trim().indexOf(path) != 0) {
-              $(this).hide();
-            }
-          });
-        }, 500);
-      }
-      if (e.keyCode == 38) {
-        if (_hdfsAutocompleteSelectedIndex <= 0) {
-          _hdfsAutocompleteSelectedIndex = $("#jHueHdfsAutocomplete ul li:visible").length - 1;
-        }
-        else {
-          _hdfsAutocompleteSelectedIndex--;
-        }
-      }
-      if (e.keyCode == 40) {
-        if (_hdfsAutocompleteSelectedIndex == $("#jHueHdfsAutocomplete ul li:visible").length - 1) {
-          _hdfsAutocompleteSelectedIndex = 0;
-        }
-        else {
-          _hdfsAutocompleteSelectedIndex++;
-        }
-      }
-      if (e.keyCode == 38 || e.keyCode == 40) {
-        smartTooltipMaker();
-        $("#jHueHdfsAutocomplete ul li").removeClass("active");
-        $("#jHueHdfsAutocomplete ul li:visible").eq(_hdfsAutocompleteSelectedIndex).addClass("active");
-        $("#jHueHdfsAutocomplete .popover-content").scrollTop($("#jHueHdfsAutocomplete ul li:visible").eq(_hdfsAutocompleteSelectedIndex).prevAll().length * $("#jHueHdfsAutocomplete ul li:visible").eq(_hdfsAutocompleteSelectedIndex).outerHeight());
-      }
-      if ((e.keyCode == 32 && e.ctrlKey) || e.keyCode == 191) {
-        smartTooltipMaker();
-        showHdfsAutocomplete();
-      }
-      if (e.keyCode == 13) {
-        if (_hdfsAutocompleteSelectedIndex > -1) {
-          $("#jHueHdfsAutocomplete ul li:visible").eq(_hdfsAutocompleteSelectedIndex).click();
-        }
-        else {
-          _this.options.onEnter($(this));
-        }
-        $("#jHueHdfsAutocomplete").hide();
-        _hdfsAutocompleteSelectedIndex = -1;
-      }
-    });
-
-    if (_this.options.showOnFocus){
-      _el.on("focus", function(){
-        showHdfsAutocomplete();
-      });
-    }
-
-    var _pauseBlur = false;
-
-    _el.blur(function () {
-      if (!_pauseBlur) {
-        $(document.body).off("contextmenu");
-        $("#jHueHdfsAutocomplete").hide();
-        _this.options.onBlur();
-      }
-    });
-
-    var BASE_PATH = "/filebrowser/view=";
-    var _currentFiles = [];
-
-    function showHdfsAutocomplete(callback) {
-      var base = "";
-      var path = _el.val();
-      var hasScheme = path.indexOf(":/") >= 0;
-      var isRelative = !hasScheme && path.charAt(0) !== "/";
-      if (isRelative && _this.options.root) {
-        base += _this.options.root;
-      }
-      var autocompleteUrl = BASE_PATH + base + path;
-      $.getJSON(autocompleteUrl + "?pagesize=1000&format=json", function (data) {
-        _currentFiles = [];
-        if (data.error == null) {
-          $(data.files).each(function (cnt, item) {
-            if (item.name != ".") {
-              var ico = "fa-file-o";
-              if (item.type == "dir") {
-                ico = "fa-folder";
-              }
-              _currentFiles.push('<li class="hdfsAutocompleteItem" data-value="' + hueUtils.escapeOutput(item.name) + '"><i class="fa ' + ico + '"></i> ' + escapeOutput(item.name) + '</li>');
-            }
-          });
-          window.setTimeout(function () {
-            $("#jHueHdfsAutocomplete").css("top", _el.offset().top + _el.outerHeight() - 1).css("left", _el.offset().left).width(_el.outerWidth() - 4);
-            $("#jHueHdfsAutocomplete").find("ul").empty().html(_currentFiles.join(""));
-            $("#jHueHdfsAutocomplete").find("li").on("click", function (e) {
-              smartTooltipMaker();
-              e.preventDefault();
-              var item = $(this).text().trim();
-              if (item == "..") { // one folder up
-                path = path.substring(0, path.lastIndexOf("/"));
-              } else {
-                path = path + (path.charAt(path.length - 1) == "/" ? "" : "/") + item;
-              }
-              _el.val(base + path);
-              if ($(this).html().indexOf("folder") > -1) {
-                _el.val(_el.val() + "/");
-                _this.options.onPathChange(_el.val());
-                showHdfsAutocomplete();
-              }
-              else {
-                _this.options.onEnter(_el);
-              }
-            });
-            $("#jHueHdfsAutocomplete").show();
-            setHueBreadcrumbCaretAtEnd(_this.element);
-            if ("undefined" != typeof callback) {
-              callback();
-            }
-          }, 100);  // timeout for IE8
-        }
-      });
-    }
-
-    $(document).on("mouseenter", ".hdfsAutocompleteItem", function () {
-      _pauseBlur = true;
-    });
-
-    $(document).on("mouseout", ".hdfsAutocompleteItem", function () {
-      _pauseBlur = false;
-    })
-
-    function guessHdfsPath(lastChars) {
-      var possibleMatches = [];
-      for (var i = 0; i < _currentFiles.length; i++) {
-        if (($(_currentFiles[i]).text().trim().indexOf(lastChars) == 0 || lastChars == "") && $(_currentFiles[i]).text().trim() != "..") {
-          possibleMatches.push(_currentFiles[i]);
-        }
-      }
-      if (possibleMatches.length == 1) {
-        _el.val(_el.val() + $(possibleMatches[0]).text().trim().substr(lastChars.length));
-        if ($(possibleMatches[0]).html().indexOf("folder") > -1) {
-          _el.val(_el.val() + "/");
-          showHdfsAutocomplete();
-        }
-      }
-      else if (possibleMatches.length > 1) {
-        // finds the longest common prefix
-        var possibleMatchesPlain = [];
-        for (var z = 0; z < possibleMatches.length; z++) {
-          possibleMatchesPlain.push($(possibleMatches[z]).text().trim());
-        }
-        var arr = possibleMatchesPlain.slice(0).sort(),
-            word1 = arr[0], word2 = arr[arr.length - 1],
-            j = 0;
-        while (word1.charAt(j) == word2.charAt(j))++j;
-        var match = word1.substring(0, j);
-        _el.val(_el.val() + match.substr(lastChars.length));
-      }
-    }
-  };
-
-  Plugin.prototype.setOptions = function (options) {
-    this.options = $.extend({}, defaults, options);
-  };
-
-
-  $.fn[pluginName] = function (options) {
-    return this.each(function () {
-      if (!$.data(this, 'plugin_' + pluginName)) {
-        $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
-      }
-      else {
-        $.data(this, 'plugin_' + pluginName).setOptions(options);
-      }
-    });
-  }
-
-  $[pluginName] = function (options) {
-    if (typeof console != "undefined") {
-      console.warn("$(elem).jHueHdfsAutocomplete() is a preferred call method.");
-    }
-    $(options.element).jHueHdfsAutocomplete(options);
-  };
-
-})(jQuery, window, document);

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

@@ -169,7 +169,6 @@ if USE_NEW_EDITOR.get():
   <script src="${ static('desktop/ext/js/tzdetect.js') }" type="text/javascript" charset="utf-8"></script>
   <script src="${ static('desktop/ext/js/knockout.validation.min.js') }"></script>
   <script src="${ static('desktop/js/ko.switch-case.js') }"></script>
-  <script src="${ static('desktop/ext/js/dropzone.min.js') }"></script>
 
 % if user.is_authenticated():
 

+ 0 - 7
desktop/core/src/desktop/templates/hue.mako

@@ -460,11 +460,6 @@ ${ render_bundle('hue') | n,unicode }
 <script src="${ static('desktop/ext/js/moment-timezone-with-data.min.js') }" type="text/javascript" charset="utf-8"></script>
 <script src="${ static('desktop/ext/js/tzdetect.js') }" type="text/javascript" charset="utf-8"></script>
 
-<script src="${ static('desktop/js/jquery.hiveautocomplete.js') }"></script>
-<script src="${ static('desktop/js/jquery.tablescroller.js') }"></script>
-<script src="${ static('desktop/js/jquery.tableextender.js') }"></script>
-<script src="${ static('desktop/js/jquery.tableextender2.js') }"></script>
-<script src="${ static('desktop/js/jquery.scrollleft.js') }"></script>
 <script src="${ static('desktop/js/jquery.scrollup.js') }"></script>
 <script src="${ static('desktop/js/jquery.huedatatable.js') }"></script>
 
@@ -480,8 +475,6 @@ ${ render_bundle('hue') | n,unicode }
 <script src="${ static('desktop/js/ace.extended.js') }"></script>
 <script>ace.config.set("basePath", "/static/desktop/js/ace");</script>
 
-<script src="${ static('desktop/ext/js/dropzone.min.js') }"></script>
-
 <script src="${ static('desktop/js/hue.colors.js') }"></script>
 
 <script src="${ static('desktop/js/sqlFunctions.js') }"></script>

+ 0 - 2
desktop/libs/indexer/src/indexer/templates/importer.mako

@@ -40,8 +40,6 @@ ${ commonheader(_("Importer"), "indexer", user, request, "60px") | n,unicode }
 <script src="${ static('desktop/js/hue.json.js') }"></script>
 
 
-<script src="${ static('desktop/js/jquery.hiveautocomplete.js') }" type="text/javascript" charset="utf-8"></script>
-<script src="${ static('desktop/ext/js/jquery/plugins/jquery-ui-1.10.4.custom.min.js') }"></script>
 <script src="${ static('desktop/ext/js/selectize.min.js') }"></script>
 <script src="${ static('desktop/ext/js/selectize-plugin-clear.js') }"></script>
 <script src="${ static('metastore/js/metastore.ko.js') }"></script>

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

@@ -121,7 +121,6 @@ from desktop.auth.backend import is_admin
 <!--[if IE 9]>
   <script src="${ static('desktop/ext/js/classList.min.js') }" type="text/javascript" charset="utf-8"></script>
 <![endif]-->
-<script src="${ static('desktop/ext/js/medium-editor.min.js') }" type="text/javascript" charset="utf-8"></script>
 
 <%namespace name="dashboard" file="/common_dashboard.mako" />
 <%namespace name="sqlSyntaxDropdown" file="/sql_syntax_dropdown.mako" />

+ 10 - 0
package-lock.json

@@ -2806,6 +2806,11 @@
       "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
       "dev": true
     },
+    "dropzone": {
+      "version": "5.5.1",
+      "resolved": "https://registry.npmjs.org/dropzone/-/dropzone-5.5.1.tgz",
+      "integrity": "sha512-3VduRWLxx9hbVr42QieQN25mx/I61/mRdUSuxAmDGdDqZIN8qtP7tcKMa3KfpJjuGjOJGYYUzzeq6eGDnkzesA=="
+    },
     "duplexer": {
       "version": "0.1.1",
       "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
@@ -5771,6 +5776,11 @@
         "safe-buffer": "^5.1.2"
       }
     },
+    "medium-editor": {
+      "version": "5.23.3",
+      "resolved": "https://registry.npmjs.org/medium-editor/-/medium-editor-5.23.3.tgz",
+      "integrity": "sha512-he9/TdjX8f8MGdXGfCs8AllrYnqXJJvjNkDKmPg3aPW/uoIrlRqtkFthrwvmd+u4QyzEiadhCCM0EwTiRdUCJw=="
+    },
     "mem": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz",

+ 2 - 0
package.json

@@ -17,6 +17,7 @@
     "node": ">=0.10.0"
   },
   "dependencies": {
+    "dropzone": "5.5.1",
     "filesize": "4.0.0",
     "jquery": "3.3.1",
     "jquery-ui": "1.12.1",
@@ -30,6 +31,7 @@
     "less": "3.9.0",
     "localforage": "1.7.3",
     "lodash": "4.17.11",
+    "medium-editor": "5.23.3",
     "minimist": "^1.2.0",
     "page": "1.8.6",
     "selectize": "0.12.6",

+ 1 - 1
webpack-stats.json

@@ -1 +1 @@
-{"status":"done","chunks":{"hue":[{"name":"hue-bundle-cd1cd1feafc6ddb99531.js","path":"/Users/jahlen/dev/hue/desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-cd1cd1feafc6ddb99531.js"},{"name":"hue-bundle-cd1cd1feafc6ddb99531.js.map","path":"/Users/jahlen/dev/hue/desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-cd1cd1feafc6ddb99531.js.map"}],"sqlSyntaxWebWorker":[{"name":"sqlSyntaxWebWorker-bundle-cd1cd1feafc6ddb99531.js","path":"/Users/jahlen/dev/hue/desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-cd1cd1feafc6ddb99531.js"},{"name":"sqlSyntaxWebWorker-bundle-cd1cd1feafc6ddb99531.js.map","path":"/Users/jahlen/dev/hue/desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-cd1cd1feafc6ddb99531.js.map"}]}}
+{"status":"done","chunks":{"hue":[{"name":"hue-bundle-c56027ed5fcc7f4abc0b.js","path":"/Users/jahlen/dev/hue/desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-c56027ed5fcc7f4abc0b.js"},{"name":"hue-bundle-c56027ed5fcc7f4abc0b.js.map","path":"/Users/jahlen/dev/hue/desktop/core/src/desktop/static/desktop/js/bundles/hue-bundle-c56027ed5fcc7f4abc0b.js.map"}],"sqlSyntaxWebWorker":[{"name":"sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js","path":"/Users/jahlen/dev/hue/desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js"},{"name":"sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js.map","path":"/Users/jahlen/dev/hue/desktop/core/src/desktop/static/desktop/js/bundles/sqlSyntaxWebWorker-bundle-c56027ed5fcc7f4abc0b.js.map"}]}}

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff