Quellcode durchsuchen

HUE-8988 [frontend] Extract import documents modal to a ko component

Johan Ahlen vor 6 Jahren
Ursprung
Commit
811c673349

+ 7 - 9
desktop/core/src/desktop/js/doc/hueFileEntry.js

@@ -682,9 +682,7 @@ class HueFileEntry {
 
   closeUploadModal() {
     if (this.app === 'documents') {
-      $('#importDocumentsModal').modal('hide');
-      $('#importDocumentData').modal('hide');
-      $('#importDocumentInput').val('');
+      huePubSub.publish('hide.import.documents.modal');
     }
     // Allow the modal to hide
     window.setTimeout(() => {
@@ -694,7 +692,7 @@ class HueFileEntry {
     }, 400);
   }
 
-  upload() {
+  upload(importSuccessCallback) {
     const self = this;
     if (
       document.getElementById('importDocumentInput').files.length > 0 &&
@@ -712,11 +710,11 @@ class HueFileEntry {
           self.uploadComplete(true);
           huePubSub.publish('assist.document.refresh');
           self.load();
-
-          $('#importDocumentsModal').modal('hide');
-          $('#importDocumentData').modal('show');
-
           self.importedDocSummary(data);
+
+          if (importSuccessCallback) {
+            importSuccessCallback();
+          }
         },
         progressHandler: event => {
           $('#importDocumentsProgress').val(Math.round((event.loaded / event.total) * 100));
@@ -750,7 +748,7 @@ class HueFileEntry {
 
   showUploadModal() {
     if (this.app === 'documents' && !this.isTrash() && !this.isTrashed()) {
-      $('#importDocumentsModal').modal('show');
+      huePubSub.publish('show.import.documents.modal', { fileEntry: this });
     }
   }
 

+ 183 - 0
desktop/core/src/desktop/js/ko/components/ko.importDocumentsModal.js

@@ -0,0 +1,183 @@
+// 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 ko from 'knockout';
+
+import componentUtils from './componentUtils';
+import huePubSub from 'utils/huePubSub';
+import I18n from 'utils/i18n';
+import HueFileEntry from '../../doc/hueFileEntry';
+
+const TEMPLATE = `
+<div class="modal-header">
+  <button type="button" class="close" data-dismiss="modal" aria-label="${I18n(
+    'Close'
+  )}"><span aria-hidden="true">&times;</span></button>
+  <!-- ko if: isHistory -->
+  <h2 class="modal-title">${I18n('Import Query History')}</h2>
+  <!-- /ko -->
+  <!-- ko ifnot: isHistory -->
+  <h2 class="modal-title">${I18n('Import Hue Documents')}</h2>
+  <!-- /ko -->
+</div>
+
+<!-- ko ifnot: imported --> 
+<div class="modal-body">
+  <!-- ko with: activeEntry -->
+  <form id="importDocumentsForm" class="form-horizontal" style="display: inline" enctype="multipart/form-data">
+    <div data-bind="visible: uploading() || uploadComplete()">
+      <span data-bind="visible: uploading()">${I18n('Importing...')}</span>
+      <span data-bind="visible: !uploadFailed() && uploadComplete()">${I18n(
+        'Import complete!'
+      )}</span>
+      <span data-bind="visible: uploadFailed">${I18n('Import failed!')}</span>
+      <progress data-bind="visible: uploading() || uploadComplete()" id="importDocumentsProgress" value="0" max="100" style="width: 560px;"></progress>
+    </div>
+    <div class="pull-right">
+      <!-- ko ifnot: uploading() || uploadComplete() -->
+      <input type="button" class="btn" data-clear="fileupload" data-bind="click: closeUploadModal" value="${I18n(
+        'Cancel'
+      )}" />
+      <input type="submit" class="btn btn-danger" data-clear="fileupload" data-bind="enable: importEnabled, click: function() { upload($parent.importComplete) }" value="${I18n(
+        'Import'
+      )}" />
+      <!-- /ko -->
+      <!-- ko if: uploading() || uploadComplete() -->
+      <input type="button" class="btn" data-clear="fileupload" data-bind="click: closeUploadModal" value="${I18n(
+        'Close'
+      )}" />
+      <!-- /ko -->
+    </div>
+
+    <div class="fileupload fileupload-new" data-provides="fileupload" data-bind="visible: !uploading() && !uploadComplete()">
+      <span class="btn btn-file">
+        <span class="fileupload-new">${I18n('Select json file')}</span>
+        <span class="fileupload-exists">${I18n('Change')}</span>
+        <input id="importDocumentInput" type="file" name="documents" accept=".json" data-bind="value: selectedImportFile" />
+      </span>
+      &nbsp;&nbsp;<span class="fileupload-preview"></span>
+      <a href="#" class="fileupload-exists" data-clear="fileupload"><i class="fa fa-times"></i></a>
+    </div>
+    <input type="hidden" name="path" data-bind="value: definition().path" />
+  </form>
+  <!-- /ko -->
+</div>
+<!-- /ko -->
+<!-- ko if: imported -->
+<div class="modal-body">
+  <!-- ko with: activeEntry -->
+  <div class="center" style="display: none;" data-bind="visible: importedDocumentCount() == 0">
+    <i class="fa fa-spinner fa-spin fa-2x"></i>
+  </div>
+  <!-- ko if: importedDocumentCount() > 0 -->
+  <ul>
+    <li> ${I18n('Imported: ')} <span data-bind="text: importedDocSummary()['count']"></span></li>
+    <li> ${I18n(
+      'Created: '
+    )} <span data-bind="text: importedDocSummary()['created_count']"></span></li>
+    <li> ${I18n(
+      'Updated: '
+    )} <span data-bind="text: importedDocSummary()['updated_count']"></span></li>
+  </ul>
+
+  <!-- ko ifnot: showTable() -->
+  <a href="javascript:void(0)" class="margin-left-10 margin-top-10" data-bind="click: toggleShowTable">${I18n(
+    'Show Details'
+  )} <i class="fa fa-caret-down"></i></a>
+  <!-- /ko -->
+  <!-- ko if: showTable() -->
+  <a href="javascript:void(0)" class="margin-left-10 margin-top-10" data-bind="click: toggleShowTable">${I18n(
+    'Hide Details'
+  )} <i class="fa fa-caret-up"></i></a>
+  <table class="table table-condensed">
+    <thead>
+      <tr>
+        <th>${I18n('Name')}</th>
+        <th>${I18n('Type')}</th>
+        <th>${I18n('Owner')}</th>
+      </tr>
+    </thead>
+    <tbody data-bind="foreach: importedDocSummary()['documents']">
+      <tr>
+        <td data-bind="text: $data.name"> </td>
+        <td data-bind="text: $data.type"> </td>
+        <td data-bind="text: $data.owner"> </td>
+      </tr>
+    </tbody>
+  </table>
+  <!-- /ko -->
+  <!-- /ko -->
+  <!-- /ko -->
+</div>
+<!-- /ko -->
+`;
+
+class ImportDocumentsModal {
+  constructor(params) {
+    if (!params) {
+      params = {};
+    }
+    this.activeEntry = ko.observable(params.fileEntry);
+    if (!params.fileEntry) {
+      this.activeEntry(
+        new HueFileEntry({
+          activeEntry: this.activeEntry,
+          trashEntry: ko.observable(),
+          app: 'documents',
+          user: self.user,
+          activeSort: ko.observable('defaultAsc'),
+          definition: {
+            name: '/',
+            type: 'directory'
+          }
+        })
+      );
+    }
+    this.imported = ko.observable(false);
+    this.isHistory = ko.observable(params.isHistory);
+
+    this.importComplete = () => {
+      if (params.importedCallback) {
+        params.importedCallback();
+      }
+      this.imported(true);
+    };
+  }
+}
+
+componentUtils.registerComponent('import-documents-modal', undefined, TEMPLATE).then(() => {
+  huePubSub.subscribe('show.import.documents.modal', params => {
+    huePubSub.publish('hide.import.documents.modal');
+
+    const $importDocumentsModal = $(
+      '<div id="importDocumentsModal" data-bind="component: { name: \'import-documents-modal\', params: $data }" data-keyboard="true" class="modal hide fade fileupload-modal" tabindex="-1"/>'
+    );
+    $('body').append($importDocumentsModal);
+
+    ko.applyBindings(new ImportDocumentsModal(params), $importDocumentsModal[0]);
+    $importDocumentsModal.modal('show');
+  });
+
+  huePubSub.subscribe('hide.import.documents.modal', () => {
+    const $importDocumentsModal = $('#importDocumentsModal');
+    if ($importDocumentsModal.length > 0) {
+      $importDocumentsModal.modal('hide');
+      ko.cleanNode($importDocumentsModal[0]);
+      $importDocumentsModal.remove();
+    }
+  });
+});

+ 1 - 0
desktop/core/src/desktop/js/ko/ko.all.js

@@ -152,6 +152,7 @@ import 'ko/components/ko.favoriteApp';
 import 'ko/components/ko.fieldSamples';
 import 'ko/components/ko.globalSearch';
 import 'ko/components/ko.historyPanel';
+import 'ko/components/ko.importDocumentsModal';
 import 'ko/components/ko.inlineAutocomplete';
 import 'ko/components/ko.jobBrowserLinks';
 import 'ko/components/ko.multiClusterSidebar';

+ 0 - 240
desktop/core/src/desktop/static/desktop/js/document/hueDocument.js

@@ -1,240 +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.
-
-var HueDocument = (function() {
-
-  /**
-   *
-   * @param {Object} options
-   * @param {ApiHelper} options.apiHelper
-   * @param {HueFileEntry} options.fileEntry
-   *
-   * @constructor
-   */
-  function HueDocument (options) {
-    var self = this;
-    self.fileEntry = options.fileEntry;
-    self.apiHelper = options.apiHelper;
-    self.definition = ko.observable();
-    self.loaded = ko.observable(false);
-    self.loading = ko.observable(false);
-    self.hasErrors = ko.observable(false);
-    self.searchInput = ko.observable();
-    self.selectedUserOrGroup = ko.observable();
-    self.selectedPerm = ko.observable('read');
-
-
-    self.userMap = {};
-    self.idToUserMap = {};
-    self.groupMap = {};
-    self.items = [];
-  };
-
-  HueDocument.prototype.onShareAutocompleteUserEnter = function () {
-    var self = this;
-
-    searchAutoCompInput = $("#userSearchAutocomp").val();
-    selectedUserOrGroup = self.userMap[searchAutoCompInput] ? self.userMap[searchAutoCompInput] : self.groupMap[searchAutoCompInput];
-    if (selectedUserOrGroup != null) {
-      if (typeof selectedUserOrGroup.username !== 'undefined') {
-        self.definition().perms[self.selectedPerm()].users.push(selectedUserOrGroup);
-      } else {
-        self.definition().perms[self.selectedPerm()].groups.push(selectedUserOrGroup);
-      }
-      self.persistPerms();
-    }
-    $("#userSearchAutocomp").val("");
-
-  };
-
-  HueDocument.prototype.shareAutocompleteUserSource = function(request, callback) {
-    var self = this;
-    var successCallback = function (data) {
-      var JSON_USERS_GROUPS = data;
-      self.items = [];
-      $.each(JSON_USERS_GROUPS.users, function (i, user) {
-        var label = prettifyUsername(user);
-        var highLightedLabel = hueUtils.highlight(label, request.term);
-        self.userMap[label] = user;
-        self.items.push({
-          data: {
-            "icon": "fa fa-user",
-            "label": highLightedLabel
-          },
-          value: label
-        });
-        self.idToUserMap[user.id] = user;
-      });
-      $.each(JSON_USERS_GROUPS.groups, function (i, group) {
-        self.groupMap[group.name] = group;
-        var highLightedLabel = hueUtils.highlight(group.name, request.term);
-        self.items.push({
-          data: {
-            "icon": "fa fa-users",
-            "label": highLightedLabel
-          },
-          value: group.name
-        });
-      });
-
-      if(self.items.length == 0){
-        self.items.push({
-          'noMatch': true
-        });
-      }
-
-      callback(self.items);
-
-      }
-
-    self.apiHelper.fetchUsersAndGroups({
-      data: {filter: request.term},
-      successCallback: successCallback,
-      errorCallback: errorCallback
-    });
-  };
-
-  HueDocument.prototype.persistPerms = function () {
-    var self = this;
-    var postPerms = {
-      read: {
-        user_ids: $.map(self.definition().perms.read.users, function (user) { return user.id }),
-        group_ids: $.map(self.definition().perms.read.groups, function (group) { return group.id }),
-      },
-      write: {
-        user_ids: $.map(self.definition().perms.write.users, function (user) { return user.id }),
-        group_ids: $.map(self.definition().perms.write.groups, function (group) { return group.id }),
-      }
-    };
-
-    $.post("/desktop/api2/doc/share", {
-      uuid: JSON.stringify(self.fileEntry.definition().uuid),
-      data: JSON.stringify(postPerms)
-    }, function (response) {
-      if (response != null) {
-        if (response.status != 0) {
-          $(document).trigger("error", "There was an error processing your action: " + response.message);
-        } else {
-          self.load();
-        }
-      }
-    }).fail(function (response) {
-      $(document).trigger("error", "There was an error processing your action: " + response.responseText);
-    });
-  };
-
-  HueDocument.prototype.load = function () {
-    var self = this;
-    if (self.loading()) {
-      return;
-    }
-
-    self.loading(true);
-    self.hasErrors(false);
-
-    var fetchDocumentsSuccessCallback = function (data) {
-      readusers = data.document.perms.read.users.map(function(user){return user.id});
-      writeusers = data.document.perms.write.users.map(function(user){return user.id});
-      allusers = readusers.concat(writeusers);
-      if (allusers.length > 0) {
-        var successCallback = function (response) {
-          $.each(response.users, function (i, user) {
-            // Needed for getting prettyusername of already shared users
-            self.idToUserMap[user.id] = user;
-          });
-          self.definition(data.document);
-        };
-        self.apiHelper.fetchUsersByIds({
-          userids: JSON.stringify(allusers),
-          successCallback: successCallback,
-          errorCallback: errorCallback
-        });
-      } else {
-        self.definition(data.document);
-      }
-    }
-
-    var fetchFunction = function () {
-      self.apiHelper.fetchDocument({
-        uuid: self.fileEntry.definition().uuid
-      }).done(function (data) {
-        fetchDocumentsSuccessCallback(data);
-        self.loading(false);
-        self.loaded(true);
-      }).fail(function () {
-        self.hasErrors(true);
-        self.loading(false);
-        self.loaded(true);
-      })
-    };
-
-    fetchFunction();
-  };
-
-
-  HueDocument.prototype.prettifyUsernameById = function (id) {
-    var self = this;
-    return self.prettifyUserName(self.idToUserMap[id]);
-  }
-
-  HueDocument.prototype.prettifyUserName = function (user) {
-    user.prettyName = '';
-    if (user.first_name) {
-      user.prettyName += user.first_name + ' ';
-    }
-    if (user.last_name) {
-      user.prettyName += user.last_name + ' ';
-    }
-    if (user.prettyName) {
-      user.prettyName += '(' + user.username + ')';
-    } else {
-      user.prettyName += user.username;
-    }
-    return user.prettyName;
-  };
-
-  HueDocument.prototype.removeFromPerms = function (perms, id) {
-    var self = this;
-    $(perms).each(function (cnt, item) {
-      if (item.id == id) {
-        perms.splice(cnt, 1);
-      }
-    });
-    self.persistPerms();
-  };
-
-  HueDocument.prototype.removeUserReadShare = function (user) {
-    var self = this;
-    self.removeFromPerms(self.definition().perms.read.users, user.id);
-  };
-
-  HueDocument.prototype.removeUserWriteShare = function (user) {
-    var self = this;
-    self.removeFromPerms(self.definition().perms.write.users, user.id);
-  };
-
-  HueDocument.prototype.removeGroupReadShare = function (group) {
-    var self = this;
-    self.removeFromPerms(self.definition().perms.read.groups, group.id);
-  };
-
-  HueDocument.prototype.removeGroupWriteShare = function (group) {
-    var self = this;
-    self.removeFromPerms(self.definition().perms.write.groups, group.id);
-  };
-
-  return HueDocument;
-})();

+ 0 - 868
desktop/core/src/desktop/static/desktop/js/document/hueFileEntry.js

@@ -1,868 +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.
-
-var HueFileEntry = (function () {
-  var self = this;
-  self.loading = ko.observable(false);
-
-  var sorts = {
-    defaultAsc: function (a, b) {
-      if (a.isDirectory() && !b.isDirectory()) {
-        return -1;
-      }
-      if (!a.isDirectory() && b.isDirectory()) {
-        return 1;
-      }
-      if (a.isDirectory() && b.isDirectory()) {
-        return sorts.nameAsc(a, b);
-      }
-      return sorts.lastModifiedDesc(a, b);
-    },
-    nameAsc: function (a, b) {
-      return a.definition().name.localeCompare(b.definition().name);
-    },
-    nameDesc: function (a, b) {
-      return sorts.nameAsc(b, a);
-    },
-    descriptionAsc: function (a, b) {
-      return a.definition().description.localeCompare(b.definition().description);
-    },
-    descriptionDesc: function (a, b) {
-      return sorts.descriptionAsc(b, a);
-    },
-    typeAsc: function (a, b) {
-      return a.definition().type.localeCompare(b.definition().type);
-    },
-    typeDesc: function (a, b) {
-      return sorts.typeAsc(b, a);
-    },
-    ownerAsc: function (a, b) {
-      return a.definition().owner.localeCompare(b.definition().owner);
-    },
-    ownerDesc: function (a, b) {
-      return sorts.ownerAsc(b, a);
-    },
-    lastModifiedAsc: function (a, b) {
-      return a.definition().last_modified_ts - b.definition().last_modified_ts;
-    },
-    lastModifiedDesc: function (a, b) {
-      return sorts.lastModifiedAsc(b, a);
-    }
-  };
-
-  /**
-   *
-   * @param {Object} options
-   * @param {ApiHelper} options.apiHelper
-   * @param {Object} options.definition
-   * @param {Function} options.activeEntry - The observable keeping track of the current open directory
-   * @param {Function} options.trashEntry - The observable keeping track of the trash directory
-   * @param {HueFolder} options.parent
-   * @param {string} options.app - Currently only 'documents' is supported
-   * @param {string} options.user
-   *
-   * @constructor
-   */
-  function HueFileEntry (options) {
-    var self = this;
-    self.activeEntry = options.activeEntry;
-    self.trashEntry = options.trashEntry;
-    self.parent = options.parent;
-    self.definition = ko.observable(options.definition);
-    self.apiHelper = options.apiHelper;
-    self.app = options.app;
-    self.user = options.user;
-    self.superuser = options.superuser;
-    self.serverTypeFilter = options.serverTypeFilter || ko.observable({ type: 'all' });
-    self.statsVisible = ko.observable(false);
-    self.highlight = ko.observable(false);
-
-    self.document = ko.observable();
-    self.selectedDocsWithDependents = ko.observable([]);
-    self.importedDocSummary = ko.observable();
-    self.showTable = ko.observable();
-    self.entries = ko.observableArray([]);
-
-    // Filter is only used in the assist panel at the moment
-    self.isFilterVisible = ko.observable(false);
-    self.filter = ko.observable('').extend({ rateLimit: 400 });
-
-    self.typeFilter = options.typeFilter || ko.observable(DOCUMENT_TYPES[0]); // First one is always 'all'
-
-    self.isFilterVisible.subscribe(function (newValue) {
-      if (!newValue && self.filter()) {
-        self.filter('');
-      }
-    });
-
-    self.filteredEntries = ko.pureComputed(function () {
-      var filter = self.filter().toLowerCase();
-      var typeFilter = self.typeFilter().type;
-      if (filter || typeFilter !== 'all') {
-        return self.entries().filter(function (entry) {
-          var entryType = entry.definition().type;
-          return (typeFilter === 'all' || entryType === typeFilter || entryType === 'directory')
-            && (!filter || entry.definition().name.toLowerCase().indexOf(filter) !== -1 ||
-            (window.DOCUMENT_TYPE_I18n[entryType] && window.DOCUMENT_TYPE_I18n[entryType].toLowerCase().indexOf(filter) !== -1) ||
-            entry.definition().description.toLowerCase().indexOf(filter) !== -1);
-        })
-      }
-      return self.entries();
-    });
-
-    self.getSelectedDocsWithDependents = function() {
-      self.selectedDocsWithDependents([]);
-      var uuids = self.selectedEntries().map(function(entry) {
-        return entry.definition().uuid;
-      }).join(',');
-
-      var data = {
-        'uuids': uuids,
-        'data': 'false',
-        'dependencies': 'true'
-      };
-
-      $.get('/desktop/api2/doc/', data, function (response) {
-        var docsWithDependents = [];
-        if (response && response.data_list) {
-          for (var index = 0; index < response.data_list.length; index++) {
-            docsWithDependents.push({'name': response.data_list[index].document.name, 'dependents': response.data_list[index].dependents})
-          }
-        }
-        self.selectedDocsWithDependents(docsWithDependents);
-      }).fail(function (response) {
-        $(document).trigger("error", "Error getting document data: " + response.responseText);
-      });
-    };
-
-    self.isTrash = ko.pureComputed(function () {
-      return self.definition().name === '.Trash';
-    });
-
-    self.isTrashed = ko.pureComputed(function () {
-      if (typeof self.parent !== 'undefined' && self.parent !== null) {
-        return self.parent.isTrash() || self.parent.isTrashed();
-      }
-      return false;
-    });
-
-    self.isRoot = ko.pureComputed(function () {
-      return self.definition().name === '';
-    });
-
-    self.isDirectory = ko.pureComputed(function () {
-      return self.definition().type === 'directory';
-    });
-
-    self.isShared = ko.pureComputed(function () {
-      var perms = self.definition().perms;
-      return perms && (perms.read.users.length > 0 || perms.read.groups.length > 0 || perms.write.users.length > 0 || perms.write.groups.length > 0);
-    });
-
-    self.isSharedWithMe = ko.pureComputed(function () {
-      return self.user !== self.definition().owner;
-    });
-
-    self.canModify = ko.pureComputed(function () {
-      var perms = self.definition().perms;
-      return !self.isSharedWithMe() || self.superuser || (perms && (perms.write.users.filter(function (user) {
-            return user.username == self.user;
-          }).length > 0
-          || perms.write.groups.filter(function (writeGroup) {
-            return LOGGED_USERGROUPS.indexOf(writeGroup.name) !== -1
-          }).length > 0));
-    });
-
-    self.canReshare = ko.pureComputed(function () {
-      if (! self.isSharedWithMe()) {
-        return true;
-      }
-      var activePerms = {};
-      var target = self;
-      while (target.parent && !target.isShared()) {
-        target = target.parent;
-      }
-      return target.canModify();
-    });
-
-    self.entriesToDelete = ko.observableArray();
-    self.deletingEntries = ko.observable(false);
-
-    self.selected = ko.observable(false);
-
-    self.loaded = ko.observable(false);
-    self.loading = ko.observable(false);
-    self.hasErrors = ko.observable(false);
-    self.uploading = ko.observable(false);
-    self.uploadComplete = ko.observable(false);
-    self.uploadFailed = ko.observable(false);
-    self.selectedImportFile = ko.observable('');
-
-    self.importEnabled = ko.pureComputed(function () {
-      return self.selectedImportFile() !== '';
-    });
-
-    self.activeSort = options.activeSort;
-
-    self.selectedEntries = ko.pureComputed(function () {
-      return $.grep(self.entries(), function (entry) {
-        return entry.selected();
-      });
-    });
-
-    self.sharedWithMeSelected = ko.pureComputed(function () {
-      return self.selectedEntries().filter(function (entry) {
-        return entry.isSharedWithMe();
-      }).length > 0;
-    });
-
-    self.directorySelected = ko.pureComputed(function () {
-      return self.selectedEntries().filter(function (entry) {
-        return entry.isDirectory();
-      }).length > 0;
-    });
-
-    self.selectedEntry = ko.pureComputed(function () {
-      if (self.selectedEntries().length === 1) {
-        return self.selectedEntries()[0];
-      }
-      return null;
-    });
-
-    self.breadcrumbs = ko.pureComputed(function () {
-      var result = [];
-      var lastParent = self.parent;
-      while (lastParent) {
-        result.unshift(lastParent);
-        lastParent = lastParent.parent;
-      }
-      return result;
-    });
-  }
-
-  HueFileEntry.prototype.getDirectory = function () {
-    var self = this;
-
-    if (! self.definition() || self.isRoot()) {
-      return null;
-    }
-    else {
-      return self.definition().uuid;
-    }
-  };
-
-  HueFileEntry.prototype.highlightInside = function (uuid) {
-    var self = this;
-    self.typeFilter(DOCUMENT_TYPES[0]);
-    var foundEntry;
-    self.entries().forEach(function (entry) {
-      entry.highlight(false);
-      if (entry.definition() && entry.definition().uuid === uuid) {
-        foundEntry = entry;
-      }
-    });
-    if (foundEntry) {
-      if (foundEntry.definition().type === 'directory') {
-        self.activeEntry(foundEntry);
-        if (!foundEntry.entries().length) {
-          foundEntry.load();
-        }
-      } else {
-        window.setTimeout(function () {
-          huePubSub.subscribeOnce('assist.db.scrollToComplete', function () {
-            foundEntry.highlight(true);
-            // Timeout is for animation effect
-            window.setTimeout(function () {
-              foundEntry.highlight(false);
-            }, 1800);
-          });
-          huePubSub.publish('assist.db.scrollTo', foundEntry);
-        }, 0);
-      }
-    }
-  };
-
-  HueFileEntry.prototype.showContextPopover = function (entry, event, positionAdjustment) {
-    var self = this;
-    var $source = $(event.target);
-    var offset = $source.offset();
-    if (positionAdjustment) {
-      offset.left += positionAdjustment.left;
-      offset.top += positionAdjustment.top;
-    }
-
-    self.statsVisible(true);
-    huePubSub.publish('context.popover.show', {
-      data: {
-        type: 'hue',
-        definition: self.definition()
-      },
-      showInAssistEnabled: false,
-      orientation: 'right',
-      pinEnabled: false,
-      source: {
-        element: event.target,
-        left: offset.left,
-        top: offset.top - 3,
-        right: offset.left + $source.width() + 1,
-        bottom: offset.top + $source.height() - 3
-      }
-    });
-    huePubSub.subscribeOnce('context.popover.hidden', function () {
-      self.statsVisible(false);
-    });
-  };
-
-  HueFileEntry.prototype.addDirectoryParamToUrl = function (url) {
-    var self = this;
-
-    var directoryId = self.getDirectory();
-
-    if (! directoryId) {
-      return url;
-    }
-    else if (url.indexOf('?') !== -1) {
-      return url + '&directory_uuid=' + self.definition().uuid;
-    }
-    else {
-      return url + '?directory_uuid=' + self.definition().uuid;
-    }
-  };
-
-  HueFileEntry.prototype.beforeContextOpen = function () {
-    var self = this;
-    if (! self.selected()) {
-      $.each(self.parent.selectedEntries(), function (idx, entry) {
-        entry.selected(false);
-      });
-      self.selected(true);
-    }
-  };
-
-  HueFileEntry.prototype.showNewDirectoryModal = function () {
-    var self = this;
-    if (! self.isTrash() && ! self.isTrashed() && self.canModify()) {
-      $('#createDirectoryModal').modal('show');
-    }
-  };
-
-  HueFileEntry.prototype.showRenameDirectoryModal = function () {
-    var self = this;
-    if (!self.selected()) {
-      self = self.selectedEntry();
-    }
-    if (! self.isTrash() && ! self.isTrashed() && self.canModify()) {
-      $('#renameDirectoryName').val(self.definition().name);
-      $('#renameDirectoryModal').modal('show');
-    }
-  };
-
-  HueFileEntry.prototype.setSort = function (name) {
-    var self = this;
-    if (self.activeSort().indexOf(name) === -1) {
-      if (name === 'lastModified') {
-        self.activeSort('lastModifiedDesc');
-      } else {
-        self.activeSort(name + 'Asc')
-      }
-    } else if (name !== 'lastModified' && self.activeSort().indexOf('Asc') !== -1) {
-      self.activeSort(name + 'Desc');
-    } else if (name === 'lastModified' && self.activeSort().indexOf('Desc') !== -1) {
-      self.activeSort('lastModifiedAsc');
-    } else {
-      self.activeSort('defaultAsc');
-    }
-    self.entries.sort(sorts[self.activeSort()]);
-  };
-
-  HueFileEntry.prototype.showSharingModal = function (entry) {
-    var self = this;
-    if (entry) {
-      $.each(self.selectedEntries(), function (idx, otherEntry) {
-        if (otherEntry !== entry) {
-          otherEntry.selected(false);
-        }
-      });
-      entry.selected(true);
-    }
-    if (self.selectedEntry()) {
-      self.selectedEntry().loadDocument();
-      $('#shareDocumentModal').modal('show');
-    }
-  };
-
-  HueFileEntry.prototype.copy = function () {
-    var self = this;
-    if (self.selectedEntries().indexOf(self) !== -1) {
-      self.activeEntry(self.parent);
-    }
-    var copyNext = function () {
-      if (self.selectedEntries().length > 0) {
-        var nextUuid = self.selectedEntries().shift().definition().uuid;
-        self.apiHelper.copyDocument({
-          uuid: nextUuid,
-          successCallback: function () {
-            copyNext();
-          },
-          errorCallback: function () {
-            self.activeEntry().load();
-          }
-        });
-      } else {
-        huePubSub.publish('assist.document.refresh');
-        self.activeEntry().load();
-      }
-    };
-    copyNext();
-  };
-
-  HueFileEntry.prototype.loadDocument = function () {
-    var self = this;
-    self.document(new HueDocument({
-      apiHelper: self.apiHelper,
-      fileEntry: self
-    }));
-    self.document().load();
-  };
-
-  /**
-   * @param {HueFileEntry[]} entries
-   */
-  HueFileEntry.prototype.moveHere = function (entries) {
-    var self = this;
-    if (self.app === "documents") {
-      var moveNext = function () {
-        if (entries.length > 0) {
-          var nextId = entries.shift().definition().uuid;
-          self.apiHelper.moveDocument({
-            successCallback: function () {
-              moveNext();
-            },
-            errorCallback: function () {
-              self.activeEntry().load();
-            },
-            sourceId: nextId,
-            destinationId: self.definition().uuid
-          });
-        } else {
-          huePubSub.publish('assist.document.refresh');
-          if (self !== self.activeEntry()) {
-            self.load();
-          }
-          self.activeEntry().load();
-        }
-      };
-    }
-    moveNext();
-  };
-
-  HueFileEntry.prototype.createNewEntry = function (options) {
-    var self = this;
-    return new HueFileEntry($.extend({
-      activeEntry: self.activeEntry,
-      activeSort: self.activeSort,
-      trashEntry: self.trashEntry,
-      apiHelper: self.apiHelper,
-      serverTypeFilter: self.serverTypeFilter,
-      typeFilter: self.typeFilter,
-      app: self.app,
-      user: self.user,
-      superuser: self.superuser
-    }, options));
-  };
-
-  HueFileEntry.prototype.search = function (query) {
-    var self = this;
-
-    var owner = self.definition().isSearchResult ? self.parent : self;
-
-    if (! query) {
-      if (self.definition().isSearchResult) {
-        self.activeEntry(self.parent);
-      }
-      return;
-    }
-
-    var resultEntry = self.createNewEntry({
-      definition: {
-        isSearchResult: true,
-        name: '"' + query + '"'
-      },
-      parent: owner
-    });
-
-    self.activeEntry(resultEntry);
-
-    resultEntry.loading(true);
-
-    self.apiHelper.searchDocuments({
-      uuid: owner.uuid,
-      query: query,
-      type: self.serverTypeFilter().type,
-      successCallback: function (data) {
-        resultEntry.hasErrors(false);
-        var newEntries = [];
-
-        $.each(data.documents, function (idx, definition) {
-          var entry = self.createNewEntry({
-            definition: definition,
-            parent: self
-          });
-          if (!entry.isTrash()) {
-            newEntries.push(entry);
-          }
-        });
-
-        resultEntry.entries(newEntries);
-        resultEntry.loading(false);
-        resultEntry.loaded(true);
-      },
-      errorCallback: function () {
-        resultEntry.hasErrors(true);
-        resultEntry.loading(false);
-        resultEntry.loaded(true);
-      }
-    });
-  };
-
-  HueFileEntry.prototype.toggleSelected = function () {
-    var self = this;
-    self.selected(! self.selected());
-  };
-
-  HueFileEntry.prototype.openSelected = function () {
-    var self = this;
-    if (self.selectedEntries().length === 1) {
-      self.selectedEntry().open();
-    }
-  };
-
-  HueFileEntry.prototype.open = function (entry, e) {
-    var self = this;
-    if (self.definition().type === 'directory') {
-      self.makeActive();
-      huePubSub.publish('file.browser.directory.opened');
-      if (!self.loaded()) {
-        self.load();
-      }
-    } else {
-      huePubSub.publish('open.link', self.definition().absoluteUrl);
-    }
-  };
-
-  HueFileEntry.prototype.load = function (successCallback, errorCallback, silenceErrors) {
-    var self = this;
-    if (self.loading()) {
-      return;
-    }
-    self.loading(true);
-
-    if (self.app === 'documents') {
-      self.apiHelper.fetchDocuments({
-        uuid: self.definition().uuid,
-        type: self.serverTypeFilter().type,
-        silenceErrors: !!silenceErrors,
-        successCallback: function(data) {
-          self.definition(data.document);
-          self.hasErrors(false);
-          var newEntries = [];
-
-          $.each(data.children, function (idx, definition) {
-            var entry = self.createNewEntry({
-              definition: definition,
-              parent: self
-            });
-            if (entry.isTrash()) {
-              self.trashEntry(entry);
-            } else {
-              newEntries.push(entry);
-            }
-          });
-
-          newEntries.sort(sorts[self.activeSort()]);
-          self.entries(newEntries);
-          if (! self.parent && data.parent) {
-            self.parent = self.createNewEntry({
-              definition: data.parent.path === '/' && self.isSharedWithMe() ? { name: '/' } : data.parent,
-              parent: null
-            });
-          }
-          self.loading(false);
-          self.loaded(true);
-
-          if (self.isRoot() && self.entries().length === 1 && self.entries()[0].definition().type === 'directory' && self.entries()[0].isSharedWithMe()) {
-            self.activeEntry(self.entries()[0]);
-            self.activeEntry().load(successCallback);
-          } else if (successCallback && typeof successCallback === 'function') {
-            successCallback();
-          }
-        },
-        errorCallback: function () {
-          self.hasErrors(true);
-          self.loading(false);
-          self.loaded(true);
-          if (errorCallback) {
-            errorCallback();
-          }
-        }
-      });
-    }
-  };
-
-  HueFileEntry.prototype.showTrash = function () {
-    var self = this;
-    if (self.trashEntry()) {
-      self.trashEntry().open();
-    }
-  };
-
-  HueFileEntry.prototype.emptyTrash = function () {
-    var self = this;
-    if (self.trashEntry()) {
-      if (! self.trashEntry().loaded()) {
-        self.trashEntry().load(function () {
-          self.entriesToDelete(self.trashEntry().entries());
-          $('#deleteEntriesModal').modal('show');
-        })
-      } else {
-        self.entriesToDelete(self.trashEntry().entries());
-        $('#deleteEntriesModal').modal('show');
-      }
-    }
-  };
-
-  HueFileEntry.prototype.moveToTrash = function () {
-    var self = this;
-    if (self.selectedEntries().length > 0 && (self.superuser || !self.sharedWithMeSelected())) {
-      self.entriesToDelete(self.selectedEntries());
-      self.removeDocuments(false);
-    }
-  };
-
-  HueFileEntry.prototype.showRestoreConfirmation = function () {
-    var self = this;
-    if (self.selectedEntries().length > 0 && (self.superuser || !self.sharedWithMeSelected())) {
-      $('#restoreFromTrashModal').modal('show');
-    }
-  };
-
-  HueFileEntry.prototype.showDeleteConfirmation = function () {
-    var self = this;
-    if (self.selectedEntries().length > 0 && (self.superuser || !self.sharedWithMeSelected())) {
-      self.entriesToDelete(self.selectedEntries());
-      $('#deleteEntriesModal').modal('show');
-    }
-  };
-
-  HueFileEntry.prototype.removeDocuments = function (deleteForever) {
-    var self = this;
-    if (self.entriesToDelete().indexOf(self) !== -1) {
-      self.activeEntry(self.parent);
-    }
-
-    var deleteNext = function () {
-      if (self.entriesToDelete().length > 0) {
-        var nextUuid = self.entriesToDelete().shift().definition().uuid;
-        self.apiHelper.deleteDocument({
-          uuid: nextUuid,
-          skipTrash: deleteForever,
-          successCallback: function () {
-            deleteNext();
-          },
-          errorCallback: function () {
-            self.activeEntry().load();
-            $('#deleteEntriesModal').modal('hide');
-            $(".modal-backdrop").remove();
-            self.deletingEntries(false);
-          }
-        });
-      } else {
-        self.deletingEntries(false);
-        huePubSub.publish('assist.document.refresh');
-        $('#deleteEntriesModal').modal('hide');
-        $(".modal-backdrop").remove();
-        self.activeEntry().load();
-      }
-    };
-    self.deletingEntries(true);
-    deleteNext();
-  };
-
-
-  HueFileEntry.prototype.closeUploadModal = function () {
-    var self = this;
-    if (self.app === 'documents') {
-      $('#importDocumentsModal').modal('hide');
-      $('#importDocumentData').modal('hide');
-      $('#importDocumentInput').val('');
-    }
-    // Allow the modal to hide
-    window.setTimeout(function () {
-      self.uploading(false);
-      self.uploadComplete(false);
-      self.uploadFailed(false);
-    }, 400);
-  };
-
-  HueFileEntry.prototype.upload = function () {
-    var self = this;
-    if (document.getElementById("importDocumentInput").files.length > 0 && self.app === 'documents') {
-      self.uploading(true);
-      self.uploadComplete(false);
-      self.uploadFailed(false);
-      self.importedDocSummary(null);
-      self.showTable(false);
-      self.apiHelper.uploadDocument({
-        formData: new FormData($('#importDocumentsForm')[0]),
-        successCallback: function (data) {
-          self.uploading(false);
-          self.uploadComplete(true);
-          huePubSub.publish('assist.document.refresh');
-          self.load();
-
-          $('#importDocumentsModal').modal('hide');
-          $('#importDocumentData').modal('show');
-
-          self.importedDocSummary(data);
-        },
-        progressHandler: function (event) {
-          $("#importDocumentsProgress").val(Math.round((event.loaded / event.total) * 100));
-        },
-        errorCallback: function () {
-          self.uploading(false);
-          self.uploadComplete(true);
-          self.uploadFailed(true);
-        }
-      });
-    }
-  };
-
-  HueFileEntry.prototype.importedDocumentCount = function () {
-    var self = this;
-    if (self.importedDocSummary()) {
-      return self.importedDocSummary()['documents'].length;
-    }
-    return 0;
-  };
-
-  HueFileEntry.prototype.toggleShowTable = function () {
-    var self = this;
-    self.showTable(!self.showTable());
-  };
-
-  HueFileEntry.prototype.makeActive = function () {
-    var self = this;
-    if (!self.loaded()) {
-      self.load();
-    }
-    self.activeEntry(this);
-  };
-
-  HueFileEntry.prototype.showUploadModal = function () {
-    var self = this;
-    if (self.app == 'documents' && ! self.isTrash() && ! self.isTrashed()) {
-      $('#importDocumentsModal').modal('show');
-    }
-  };
-
-  HueFileEntry.prototype.contextMenuDownload = function () {
-    var self = this;
-    if (self.selected()) {
-      self.parent.download();
-    } else {
-      self.downloadThis();
-    }
-  };
-
-  HueFileEntry.prototype.downloadThis = function () {
-    var self = this;
-    window.location.href = window.HUE_BASE_URL + '/desktop/api2/doc/export?documents=' + ko.mapping.toJSON([ self.definition().id ]);
-  };
-
-  HueFileEntry.prototype.download = function () {
-    var self = this;
-    if (self.app = 'documents') {
-      if (self.selectedEntries().length > 0) {
-        var ids = self.selectedEntries().map(function (entry) {
-          return entry.definition().id;
-        });
-        window.location.href = window.HUE_BASE_URL + '/desktop/api2/doc/export?documents=' + ko.mapping.toJSON([ self.definition().id ]);
-      } else {
-        self.downloadThis();
-      }
-    };
-  };
-
-  HueFileEntry.prototype.restoreFromTrash = function () {
-    var self = this;
-    if (self.app === 'documents') {
-      if (self.selectedEntries().indexOf(self) !== -1) {
-        self.activeEntry(self.parent);
-      }
-
-      if (self.selectedEntries().length > 0) {
-        var uuids = self.selectedEntries().map(function(entry) {
-          return entry.definition().uuid;
-        }).join(',');
-        self.apiHelper.restoreDocument({
-          uuids: uuids,
-          successCallback: function () {
-            huePubSub.publish('assist.document.refresh');
-            self.activeEntry().load();
-          },
-          errorCallback: function () {
-            self.activeEntry().load();
-          }
-        });
-      } else {
-        self.activeEntry().load();
-      }
-      $('#restoreFromTrashModal').modal('hide');
-    }
-  };
-
-  HueFileEntry.prototype.createDirectory = function (name) {
-    var self = this;
-    if (name && self.app === 'documents') {
-      self.apiHelper.createDocumentsFolder({
-        successCallback: function () {
-          huePubSub.publish('assist.document.refresh');
-          self.load()
-        },
-        parentUuid: self.definition().uuid,
-        name: name
-      });
-      $('#newDirectoryName').val(null)
-    }
-  };
-
-  HueFileEntry.prototype.renameDirectory = function (name) {
-    var self = this;
-    if (name && self.app === 'documents') {
-      self.apiHelper.updateDocument({
-        successCallback: function () {
-          huePubSub.publish('assist.document.refresh');
-          self.load();
-        },
-        uuid: self.definition().uuid,
-        name: name
-      });
-      $('#renameDirectoryName').val(null)
-    }
-  };
-
-  return HueFileEntry;
-})();

+ 0 - 89
desktop/core/src/desktop/templates/document_browser.mako

@@ -24,10 +24,8 @@ from desktop.views import _ko
 
 <%def name="docBrowser(is_embeddable=False)">
 
-  <script src="${ static('desktop/ext/js/bootstrap-fileupload.js') }" type="text/javascript" charset="utf-8"></script>
   <script src="${ static('desktop/ext/js/jquery/plugins/jquery.hotkeys.js') }"></script>
   <link href="${ static('desktop/css/home.css') }" rel="stylesheet">
-  <link href="${ static('desktop/ext/css/bootstrap-fileupload.css') }" rel="stylesheet">
 
   <script type="text/html" id="doc-browser-template">
     <div class="doc-browser-drag-helper">
@@ -107,93 +105,6 @@ from desktop.views import _ko
       <!-- /ko -->
     </div>
 
-    <div id="importDocumentsModal" data-keyboard="true" class="modal hide fade fileupload-modal" tabindex="-1">
-      <!-- ko with: activeEntry -->
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
-        <h2 class="modal-title">${_('Import Hue documents')}</h2>
-      </div>
-        <form id="importDocumentsForm" class="form-horizontal" style="display: inline" enctype="multipart/form-data">
-          <div class="modal-body">
-            <div data-bind="visible: uploading() || uploadComplete()">
-              <span data-bind="visible: uploading()">${ _('Importing...') }</span>
-              <span data-bind="visible: !uploadFailed() && uploadComplete()">${ _('Import complete!') }</span>
-              <span data-bind="visible: uploadFailed">${ _('Import failed!') }</span>
-              <progress data-bind="visible: uploading() || uploadComplete()" id="importDocumentsProgress" value="0" max="100" style="width: 560px;"></progress>
-            </div>
-            <div class="pull-right">
-              <!-- ko ifnot: uploading() || uploadComplete() -->
-              <input type="button" class="btn" data-clear="fileupload" data-bind="click: closeUploadModal" value="${ _('Cancel') }" />
-              <input type="submit" class="btn btn-danger" data-clear="fileupload" data-bind="enable: importEnabled, click: upload" value="${ _('Import') }" />
-              <!-- /ko -->
-              <!-- ko if: uploading() || uploadComplete() -->
-              <input type="button" class="btn" data-clear="fileupload" data-bind="click: closeUploadModal" value="${ _('Close') }" />
-              <!-- /ko -->
-            </div>
-
-            <div class="fileupload fileupload-new" data-provides="fileupload" data-bind="visible: !uploading() && !uploadComplete()">
-              <span class="btn btn-file">
-                <span class="fileupload-new">${ _('Select json file') }</span>
-                <span class="fileupload-exists">${ _('Change') }</span>
-                <input id="importDocumentInput" type="file" name="documents" accept=".json" data-bind="value: selectedImportFile" />
-              </span>
-              &nbsp;&nbsp;<span class="fileupload-preview"></span>
-              <a href="#" class="fileupload-exists" data-clear="fileupload"><i class="fa fa-times"></i></a>
-            </div>
-            ${ csrf_token(request) | n,unicode }
-            <input type="hidden" name="path" data-bind="value: definition().path" />
-          </div>
-        </form>
-      <!-- /ko -->
-    </div>
-
-    <div id="importDocumentData" data-keyboard="true" class="modal hide fade" tabindex="-1">
-      <!-- ko with: activeEntry -->
-      <div class="modal-header">
-        <button type="button" class="close" data-dismiss="modal" aria-label="${ _('Close') }"><span aria-hidden="true">&times;</span></button>
-        <h2 class="modal-title">${_('Import Hue documents')}</h2>
-      </div>
-      <div class="modal-body">
-        <div class="center" style="display: none;" data-bind="visible: importedDocumentCount() == 0">
-          <i class="fa fa-spinner fa-spin fa-2x"></i>
-        </div>
-        <!-- ko if: importedDocumentCount() > 0 -->
-          <ul>
-            <li> ${_('Imported: ')} <span data-bind="text: importedDocSummary()['count']"></span></li>
-            <li> ${_('Created: ')} <span data-bind="text: importedDocSummary()['created_count']"></span></li>
-            <li> ${_('Updated: ')} <span data-bind="text: importedDocSummary()['updated_count']"></span></li>
-          </ul>
-
-          <!-- ko ifnot: showTable() -->
-          <a href="javascript:void(0)" class="margin-left-10 margin-top-10" data-bind="click: toggleShowTable">${_('Show Details')} <i class="fa fa-caret-down"></i></a>
-          <!-- /ko -->
-          <!-- ko if: showTable() -->
-          <a href="javascript:void(0)" class="margin-left-10 margin-top-10" data-bind="click: toggleShowTable">${_('Hide Details')} <i class="fa fa-caret-up"></i></a>
-            <table class="table table-condensed">
-              <thead>
-                <tr>
-                  <th>${_('Name')}</th>
-                  <th>${_('Type')}</th>
-                  <th>${_('Owner')}</th>
-                </tr>
-              </thead>
-              <tbody data-bind="foreach: importedDocSummary()['documents']">
-                <tr>
-                  <td data-bind="text: $data.name"> </td>
-                  <td data-bind="text: $data.type"> </td>
-                  <td data-bind="text: $data.owner"> </td>
-                </tr>
-              </tbody>
-            </table>
-          <!-- /ko -->
-        <!-- /ko -->
-      </div>
-      <div class="modal-footer">
-        <input data-dismiss="modal" type="button" class="btn" value="${ _('Close') }" data-bind="click: closeUploadModal"/>
-      </div>
-      <!-- /ko -->
-    </div>
-
     <div id="renameDirectoryModal" data-keyboard="true" class="modal hide fade" tabindex="-1">
       <!-- ko with: activeEntry -->
       <form class="form-horizontal">

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

@@ -64,6 +64,7 @@
   <link rel="stylesheet" href="${ static('desktop/ext/css/leaflet.zoombox.css') }">
   <link rel="stylesheet" href="${ static('desktop/ext/css/nv.d3.min.css') }">
   <link rel="stylesheet" href="${ static('desktop/css/nv.d3.css') }">
+  <link rel="stylesheet" href="${ static('desktop/ext/css/bootstrap-fileupload.css') }" >
 
   ${ commonHeaderFooterComponents.header_i18n_redirection() }
   <%
@@ -333,6 +334,7 @@ ${ 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/ext/js/bootstrap-fileupload.js') }"></script>
 <script src="${ static('desktop/js/bootstrap-tooltip.js') }"></script>
 <script src="${ static('desktop/js/bootstrap-typeahead-touchscreen.js') }"></script>
 <script src="${ static('desktop/ext/js/bootstrap-better-typeahead.min.js') }"></script>