Procházet zdrojové kódy

HUE-9384 [ui] Fix js exceptions from document empty trash and create folder

Johan Ahlen před 5 roky
rodič
revize
df10924d81

+ 10 - 19
desktop/core/src/desktop/js/doc/hueFileEntry.js

@@ -21,6 +21,7 @@ import apiHelper from 'api/apiHelper';
 import huePubSub from 'utils/huePubSub';
 import HueDocument from 'doc/hueDocument';
 import { DOCUMENT_TYPE_I18n, DOCUMENT_TYPES } from 'doc/docSupport';
+import { SHOW_DELETE_DOC_MODAL_EVENT } from 'ko/components/ko.deleteDocModal';
 
 const SORTS = {
   defaultAsc: (a, b) => {
@@ -327,12 +328,6 @@ class HueFileEntry {
     }
   }
 
-  showNewDirectoryModal() {
-    if (!this.isTrash() && !this.isTrashed() && this.canModify()) {
-      $('#createDirectoryModal').modal('show');
-    }
-  }
-
   showRenameDirectoryModal() {
     let selectedEntry = this;
     if (!selectedEntry.selected()) {
@@ -619,14 +614,17 @@ class HueFileEntry {
 
   emptyTrash() {
     if (this.trashEntry()) {
+      const openConfirmation = () => {
+        this.trashEntry()
+          .entries()
+          .forEach(entry => entry.selected(true));
+        huePubSub.publish(SHOW_DELETE_DOC_MODAL_EVENT, this.trashEntry());
+      };
+
       if (!this.trashEntry().loaded()) {
-        this.trashEntry().load(function () {
-          this.entriesToDelete(this.trashEntry().entries());
-          $('#deleteEntriesModal').modal('show');
-        });
+        this.trashEntry().load(openConfirmation);
       } else {
-        this.entriesToDelete(this.trashEntry().entries());
-        $('#deleteEntriesModal').modal('show');
+        openConfirmation();
       }
     }
   }
@@ -644,13 +642,6 @@ class HueFileEntry {
     }
   }
 
-  showDeleteConfirmation() {
-    if (this.selectedEntries().length > 0 && (this.superuser || !this.sharedWithMeSelected())) {
-      this.entriesToDelete(this.selectedEntries());
-      $('#deleteEntriesModal').modal('show');
-    }
-  }
-
   removeDocuments(deleteForever) {
     const self = this;
     if (self.entriesToDelete().indexOf(self) !== -1) {

+ 1 - 0
desktop/core/src/desktop/js/jest/jest.init.js

@@ -22,6 +22,7 @@ import 'apps/notebook2/execution/sessionManager';
 import './jquery.setup';
 import './sqlTestUtils';
 
+import 'ext/bootstrap.2.3.2.min';
 import $ from 'jquery';
 import * as ko from 'knockout';
 import komapping from 'knockout.mapping';

+ 2 - 2
desktop/core/src/desktop/js/ko/components/__snapshots__/ko.createDirectoryModal.test.js.snap

@@ -1,7 +1,7 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`ko.createDirectoryModal.js should render component 1`] = `
-"<html><head></head><body><div id=\\"createDirectoryModal\\" data-bind=\\"descendantsComplete: descendantsComplete, component: { name: 'create-directory', params: params }\\" data-keyboard=\\"true\\" class=\\"modal hide fade\\" tabindex=\\"-1\\">
+"<html><head></head><body class=\\"modal-open\\"><div id=\\"createDirectoryModal\\" data-bind=\\"descendantsComplete: descendantsComplete, component: { name: 'create-directory', params: params }\\" data-keyboard=\\"true\\" class=\\"modal hide fade in\\" tabindex=\\"-1\\" aria-hidden=\\"false\\">
   <!-- ko with: activeEntry -->
   <form class=\\"form-horizontal\\">
     <div class=\\"modal-header\\">
@@ -17,5 +17,5 @@ exports[`ko.createDirectoryModal.js should render component 1`] = `
     </div>
   </form>
   <!-- /ko -->
-</div></body></html>"
+</div><div class=\\"modal-backdrop fade in\\"></div></body></html>"
 `;

+ 10 - 11
desktop/core/src/desktop/js/ko/components/__snapshots__/ko.deleteDocModal.test.js.snap

@@ -1,27 +1,26 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
 exports[`ko.deleteDocModal.js should render component 1`] = `
-"<html><head></head><body><div id=\\"deleteEntriesModal\\" data-bind=\\"descendantsComplete: descendantsComplete, component: { name: 'delete-entry', params: params }\\" data-keyboard=\\"true\\" class=\\"modal hide fade\\" tabindex=\\"-1\\">
-  <!-- ko with: activeEntry -->
+"<html><head></head><body class=\\"modal-open\\"><div id=\\"deleteEntriesModal\\" data-bind=\\"descendantsComplete: descendantsComplete, component: { name: 'delete-entry', params: params }\\" data-keyboard=\\"true\\" class=\\"modal hide fade in\\" tabindex=\\"-1\\" aria-hidden=\\"false\\">
   <div class=\\"modal-header\\">
     <button type=\\"button\\" class=\\"close\\" data-dismiss=\\"modal\\" aria-label=\\"Close\\"><span aria-hidden=\\"true\\">×</span></button>
-    <!-- ko if: entriesToDelete().length === 0 -->
-    <h2 class=\\"modal-title\\">The trash is empty</h2>
+    <!-- ko if: entriesToDelete().length === 0 --><!-- /ko -->
+    <!-- ko if: entriesToDelete().length > 0 -->
+    <h2 class=\\"modal-title\\"> Do you really want to delete the following document(s)? </h2>
     <!-- /ko -->
-    <!-- ko if: entriesToDelete().length > 0 --><!-- /ko -->
   </div>
   <div class=\\"modal-body\\">
-    <div class=\\"doc-browser-empty animated\\" style=\\"display: none;\\" data-bind=\\"visible: entriesToDelete().length > 0 &amp;&amp; selectedDocsWithDependents().length === 0\\">
+    <div class=\\"doc-browser-empty animated\\" style=\\"\\" data-bind=\\"visible: entriesToDelete().length > 0 &amp;&amp; selectedDocsWithDependents().length === 0\\">
       <i class=\\"fa fa-spinner fa-spin fa-2x\\"></i>
     </div>
     <ul data-bind=\\"foreach: selectedDocsWithDependents()\\"></ul>
   </div>
   <div class=\\"modal-footer\\">
-    <!-- ko if: entriesToDelete().length === 0 -->
-    <input type=\\"button\\" class=\\"btn\\" data-dismiss=\\"modal\\" value=\\"Close\\">
+    <!-- ko if: entriesToDelete().length === 0 --><!-- /ko -->
+    <!-- ko if: entriesToDelete().length > 0 -->
+    <input type=\\"button\\" class=\\"btn\\" data-dismiss=\\"modal\\" value=\\"Cancel\\">
+    <input type=\\"submit\\" data-bind=\\"click: function() { if (isTrash() || isTrashed()) { removeDocuments(true) } else { moveToTrash() } }, disable: deletingEntries\\" class=\\"btn btn-danger disable-feedback\\" value=\\"Yes\\">
     <!-- /ko -->
-    <!-- ko if: entriesToDelete().length > 0 --><!-- /ko -->
   </div>
-  <!-- /ko -->
-</div></body></html>"
+</div><div class=\\"modal-backdrop fade in\\"></div></body></html>"
 `;

+ 2 - 2
desktop/core/src/desktop/js/ko/components/assist/ko.assistDocumentsPanel.js

@@ -42,7 +42,7 @@ const TEMPLATE = `
     <li><a href="javascript: void(0);" data-bind="click: open"><i class="fa fa-fw fa-edit"></i> ${I18n(
       'Open document'
     )}</a></li>
-    <li><a href="javascript: void(0);" data-bind="click: function() { huePubSub.publish('doc.show.delete.modal', $data); activeEntry().getSelectedDocsWithDependents(); activeEntry().showDeleteConfirmation(); }"><i class="fa fa-fw fa-trash-o"></i> ${I18n(
+    <li><a href="javascript: void(0);" data-bind="click: function() { $data.selected(true); huePubSub.publish('doc.show.delete.modal', $data.parent); }"><i class="fa fa-fw fa-trash-o"></i> ${I18n(
       'Delete document'
     )}</a></li>
     <!-- /ko -->
@@ -150,7 +150,7 @@ const TEMPLATE = `
             <!-- /ko -->
             <li class="divider"></li>
             <li data-bind="css: { 'disabled': $data.isTrash() || $data.isTrashed() || !$data.canModify() }">
-              <a href="javascript:void(0);" data-bind="click: function () { $('.new-document-drop-down').removeClass('open'); huePubSub.publish('show.create.directory.modal', $data); $data.showNewDirectoryModal()}"><svg class="hi"><use xlink:href="#hi-folder"></use><use xlink:href="#hi-plus-addon"></use></svg> ${I18n(
+              <a href="javascript:void(0);" data-bind="click: function () { $('.new-document-drop-down').removeClass('open'); huePubSub.publish('show.create.directory.modal', $data); }"><svg class="hi"><use xlink:href="#hi-folder"></use><use xlink:href="#hi-plus-addon"></use></svg> ${I18n(
                 'New folder'
               )}</a>
             </li>

+ 6 - 0
desktop/core/src/desktop/js/ko/components/ko.createDirectoryModal.js

@@ -52,6 +52,10 @@ const TEMPLATE = `
 
 componentUtils.registerComponent('create-directory', undefined, TEMPLATE).then(() => {
   huePubSub.subscribe(SHOW_EVENT, docViewModel => {
+    if (docViewModel.isTrash() || docViewModel.isTrashed() || !docViewModel.canModify()) {
+      return;
+    }
+
     let $createDirectoryModal = $('#createDirectoryModal');
     if ($createDirectoryModal.length > 0) {
       ko.cleanNode($createDirectoryModal[0]);
@@ -71,5 +75,7 @@ componentUtils.registerComponent('create-directory', undefined, TEMPLATE).then((
     $('body').append($createDirectoryModal);
 
     ko.applyBindings(data, $createDirectoryModal[0]);
+
+    $createDirectoryModal.modal('show');
   });
 });

+ 6 - 1
desktop/core/src/desktop/js/ko/components/ko.createDirectoryModal.test.js

@@ -20,7 +20,12 @@ import huePubSub from 'utils/huePubSub';
 
 describe('ko.createDirectoryModal.js', () => {
   it('should render component', async () => {
-    huePubSub.publish(SHOW_EVENT, { activeEntry: ko.observable({}) });
+    huePubSub.publish(SHOW_EVENT, {
+      activeEntry: ko.observable({}),
+      isTrash: ko.observable(false),
+      isTrashed: ko.observable(false),
+      canModify: ko.observable(true)
+    });
 
     await new Promise(resolve => {
       huePubSub.subscribeOnce(SHOWN_EVENT, resolve);

+ 28 - 8
desktop/core/src/desktop/js/ko/components/ko.deleteDocModal.js

@@ -21,11 +21,11 @@ import componentUtils from './componentUtils';
 import huePubSub from 'utils/huePubSub';
 import I18n from 'utils/i18n';
 
-export const SHOW_EVENT = 'doc.show.delete.modal';
-export const SHOWN_EVENT = 'doc.delete.modal.shown';
+export const HIDE_DELETE_DOC_MODAL_EVENT = 'doc.hide.delete.modal';
+export const SHOW_DELETE_DOC_MODAL_EVENT = 'doc.show.delete.modal';
+export const DELETE_DOC_MODAL_SHOWN_EVENT = 'doc.delete.modal.shown';
 
 const TEMPLATE = `
-  <!-- ko with: activeEntry -->
   <div class="modal-header">
     <button type="button" class="close" data-dismiss="modal" aria-label="${I18n(
       'Close'
@@ -75,29 +75,49 @@ const TEMPLATE = `
     )}"/>
     <!-- /ko -->
   </div>
-  <!-- /ko -->
 `;
 
 componentUtils.registerComponent('delete-entry', undefined, TEMPLATE).then(() => {
-  huePubSub.subscribe(SHOW_EVENT, docViewModel => {
-    let $deleteEntriesModal = $('#deleteEntriesModal');
+  const removeDeleteDocModal = () => {
+    const $deleteEntriesModal = $('#deleteEntriesModal');
     if ($deleteEntriesModal.length > 0) {
       ko.cleanNode($deleteEntriesModal[0]);
       $deleteEntriesModal.remove();
     }
+  };
+
+  huePubSub.subscribe(SHOW_DELETE_DOC_MODAL_EVENT, docViewModel => {
+    removeDeleteDocModal();
+
+    if (!docViewModel.entriesToDelete().length && docViewModel.selectedEntries().length) {
+      docViewModel.entriesToDelete(docViewModel.selectedEntries());
+    }
+
+    if (
+      docViewModel.entriesToDelete().length === 0 ||
+      (docViewModel.sharedWithMeSelected() && !docViewModel.superuser)
+    ) {
+      return;
+    }
+
+    docViewModel.getSelectedDocsWithDependents();
 
     const data = {
       params: docViewModel,
       descendantsComplete: () => {
-        huePubSub.publish(SHOWN_EVENT);
+        huePubSub.publish(DELETE_DOC_MODAL_SHOWN_EVENT);
       }
     };
 
-    $deleteEntriesModal = $(
+    const $deleteEntriesModal = $(
       '<div id="deleteEntriesModal" data-bind="descendantsComplete: descendantsComplete, component: { name: \'delete-entry\', params: params }" data-keyboard="true" class="modal hide fade" tabindex="-1"></div>'
     );
     $('body').append($deleteEntriesModal);
 
     ko.applyBindings(data, $deleteEntriesModal[0]);
+
+    $deleteEntriesModal.modal('show');
   });
+
+  huePubSub.subscribe(HIDE_DELETE_DOC_MODAL_EVENT, removeDeleteDocModal);
 });

+ 9 - 7
desktop/core/src/desktop/js/ko/components/ko.deleteDocModal.test.js

@@ -15,20 +15,22 @@
 // limitations under the License.
 
 import * as ko from 'knockout';
-import { SHOWN_EVENT, SHOW_EVENT } from './ko.deleteDocModal';
+import { DELETE_DOC_MODAL_SHOWN_EVENT, SHOW_DELETE_DOC_MODAL_EVENT } from './ko.deleteDocModal';
 import huePubSub from 'utils/huePubSub';
 
 describe('ko.deleteDocModal.js', () => {
   it('should render component', async () => {
-    huePubSub.publish(SHOW_EVENT, {
-      activeEntry: ko.observable({
-        entriesToDelete: ko.observableArray(),
-        selectedDocsWithDependents: ko.observableArray()
-      })
+    huePubSub.publish(SHOW_DELETE_DOC_MODAL_EVENT, {
+      entriesToDelete: ko.observableArray(),
+      selectedEntries: ko.observableArray([{ selected: ko.observable(true) }]),
+      sharedWithMeSelected: ko.observable(false),
+      selectedDocsWithDependents: ko.observableArray(),
+      deletingEntries: ko.observable(false),
+      getSelectedDocsWithDependents: () => {}
     });
 
     await new Promise(resolve => {
-      huePubSub.subscribeOnce(SHOWN_EVENT, resolve);
+      huePubSub.subscribeOnce(DELETE_DOC_MODAL_SHOWN_EVENT, resolve);
     });
 
     expect(window.document.documentElement.outerHTML).toMatchSnapshot();

+ 4 - 5
desktop/core/src/desktop/templates/document_browser.mako

@@ -151,7 +151,7 @@ from desktop.views import _ko
                       % endif
                       <li class="divider"></li>
                       <li data-bind="css: { 'disabled': isTrash() || isTrashed() || !canModify() }">
-                        <a href="javascript:void(0);" data-bind="click: function () {  huePubSub.publish('show.create.directory.modal', $data);showNewDirectoryModal() }"><svg class="hi"><use xlink:href="#hi-folder"></use><use xlink:href="#hi-plus-addon"></use></svg> ${_('New folder')}</a>
+                        <a href="javascript:void(0);" data-bind="click: function () {  huePubSub.publish('show.create.directory.modal', $data); }"><svg class="hi"><use xlink:href="#hi-folder"></use><use xlink:href="#hi-plus-addon"></use></svg> ${_('New folder')}</a>
                       </li>
                     </ul>
                   </span>
@@ -191,7 +191,7 @@ from desktop.views import _ko
                     </li>
                     <!-- /ko -->
                     <li data-bind="css: { 'disabled': selectedEntries().length === 0 || (sharedWithMeSelected() && !superuser) }">
-                      <a href="javascript:void(0);" data-bind="click: function() {huePubSub.publish('doc.show.delete.modal', $data);getSelectedDocsWithDependents(); showDeleteConfirmation(); }"><i class="fa fa-fw fa-times"></i> <span data-bind="text:  isTrash() || isTrashed() ? '${ _ko('Delete forever') }' : '${ _ko('Move to trash') }'"></span></a>
+                      <a href="javascript:void(0);" data-bind="click: function() {huePubSub.publish('doc.show.delete.modal', $data); }"><i class="fa fa-fw fa-times"></i> <span data-bind="text:  isTrash() || isTrashed() ? '${ _ko('Delete forever') }' : '${ _ko('Move to trash') }'"></span></a>
                     </li>
                     <li data-bind="css: { 'disabled': isTrash() || isTrashed() || selectedEntry() === null || !canModify() || (selectedEntry() != null && (!selectedEntry().isDirectory() || !selectedEntry().canModify())) }">
                       <a href="javascript:void(0);" data-bind="click: function () { showRenameDirectoryModal() }"><i class="fa fa-fw fa-edit"></i> ${_('Rename folder')}</a>
@@ -282,7 +282,7 @@ from desktop.views import _ko
             <div class="doc-browser-row" data-bind="contextMenu: { scrollContainer: '.doc-browser-list', menuSelector: '.hue-context-menu', beforeOpen: beforeContextOpen }">
               <ul class="hue-context-menu">
                 <!-- ko if: isTrashed -->
-                <li><a href="javascript:void(0);" data-bind="click: function() { huePubSub.publish('doc.show.delete.modal', $data);$parent.getSelectedDocsWithDependents(); $parent.showDeleteConfirmation(); }"><i class="fa fa-fw fa-times"></i> ${ _('Delete') } <span data-bind="visible: $parent.selectedEntries().length > 1, text: '(' + $parent.selectedEntries().length + ')'"></span></a></li>
+                <li><a href="javascript:void(0);" data-bind="click: function() { huePubSub.publish('doc.show.delete.modal', $parent); }"><i class="fa fa-fw fa-times"></i> ${ _('Delete') } <span data-bind="visible: $parent.selectedEntries().length > 1, text: '(' + $parent.selectedEntries().length + ')'"></span></a></li>
                 <li><a href="javascript:void(0);" data-bind="click: function() { $parent.showRestoreConfirmation(); }"><i class="fa fa-fw fa-undo"></i> ${ _('Restore to Home') } <span data-bind="visible: $parent.selectedEntries().length > 1, text: '(' + $parent.selectedEntries().length + ')'"></span></a></li>
                 <!-- /ko -->
                 <!-- ko ifnot: isTrashed -->
@@ -291,10 +291,9 @@ from desktop.views import _ko
                 <!-- /ko -->
                 <li data-bind="css: { 'disabled': $parent.selectedEntries().length !== 1 }"><a href="javascript:void(0);" data-bind="click: open, css: { 'disabled': $parent.selectedEntries().length !== 1 }"><i class="fa fa-fw fa-file-o"></i> ${ _('Open') }</a></li>
                 <li><a href="javascript:void(0);" data-bind="click: contextMenuDownload"><i class="fa fa-fw fa-download"></i> ${ _('Download') } <span data-bind="visible: $parent.selectedEntries().length > 1, text: '(' + $parent.selectedEntries().length + ')'"></span></a></li>
-                <li data-bind="visible: ! $altDown(), css: { 'disabled' : $parent.sharedWithMeSelected()  && ! $parent.superuser }"><a href="javascript:void(0);" data-bind="click: function () { huePubSub.publish('doc.show.delete.modal', $data);$parent.getSelectedDocsWithDependents(); $parent.showDeleteConfirmation(); }, css: { 'disabled' : $parent.sharedWithMeSelected() && ! $parent.superuser }">
+                <li data-bind="css: { 'disabled' : $parent.sharedWithMeSelected()  && ! $parent.superuser }"><a href="javascript:void(0);" data-bind="click: function () { huePubSub.publish('doc.show.delete.modal', $parent); }, css: { 'disabled' : $parent.sharedWithMeSelected() && ! $parent.superuser }">
                   <i class="fa fa-fw fa-times"></i> ${ _('Move to trash') } <span data-bind="visible: $parent.selectedEntries().length > 1, text: '(' + $parent.selectedEntries().length + ')'"></span></a>
                 </li>
-                <li data-bind="visible: $altDown(), css: { 'disabled' : $parent.sharedWithMeSelected() && ! $parent.superuser }"><a href="javascript:void(0);" data-bind="click: function() { huePubSub.publish('doc.show.delete.modal', $data);$parent.getSelectedDocsWithDependents(); $parent.showDeleteConfirmation(); }, css: { 'disabled' : $parent.sharedWithMeSelected() && ! $parent.superuser}"><i class="fa fa-fw fa-times"></i> ${ _('Delete forever') } <span data-bind="visible: $parent.selectedEntries().length > 1, text: '(' + $parent.selectedEntries().length + ')'"></span></a></li>
                 <li data-bind="css: { 'disabled': $parent.selectedEntries().length !== 1 }"><a href="javascript:void(0);" data-bind="click: function() { $parent.showSharingModal(); }, css: { 'disabled': $parent.selectedEntries().length !== 1 }"><i class="fa fa-fw fa-users"></i> ${ _('Share') }</a> </li>
                 <!-- /ko -->
               </ul>