From 2a66bd40b049255532bfaa58803661042e94103a Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Thu, 9 Jan 2025 12:01:47 -0500 Subject: [PATCH 1/2] SWC-4693 - Update UploadDialogWidgetV2 to configure drag-and-drop on render, and to completely re-render when the modal is closed. EntityActionControllerImpl - Configure the uploader when EntityActionControllerImpl is configured to prepare drag-and-drop - Use a single instance of UploadDialogWidgetV2 to ensure the same component instance used to configure drag-and-drop is used when the modal is opened. - Update Drag-and-Drop initialization code to use JsInterop instead of JSNI - Remove feature flag checks for UploadDialogWidgetV2 - Delete UploadDialogWidget (v1) --- .../web/client/FeatureFlagKey.java | 3 - .../client/GlobalApplicationStateImpl.java | 106 +++++------ .../web/client/PortalGinInjector.java | 5 +- .../jsinterop/EntityUploadModalProps.java | 9 +- .../client/jsinterop/ReactComponentProps.java | 5 + .../EntityActionControllerImpl.java | 120 +++++-------- .../entity/download/UploadDialogWidget.java | 93 ---------- .../entity/download/UploadDialogWidgetV2.java | 46 ++++- .../EntityActionControllerImplTest.java | 110 +++++++++--- .../entity/download/UploadDialogTest.java | 166 ------------------ 10 files changed, 240 insertions(+), 423 deletions(-) delete mode 100644 src/main/java/org/sagebionetworks/web/client/widget/entity/download/UploadDialogWidget.java delete mode 100644 src/test/java/org/sagebionetworks/web/unitclient/widget/entity/download/UploadDialogTest.java diff --git a/src/main/java/org/sagebionetworks/web/client/FeatureFlagKey.java b/src/main/java/org/sagebionetworks/web/client/FeatureFlagKey.java index 35b1e487d8..3e1a8a56e7 100644 --- a/src/main/java/org/sagebionetworks/web/client/FeatureFlagKey.java +++ b/src/main/java/org/sagebionetworks/web/client/FeatureFlagKey.java @@ -40,9 +40,6 @@ public enum FeatureFlagKey { // If enabled, sharing settings will appear in a dialog immediately after uploading one or more files. SHOW_SHARING_SETTINGS_AFTER_UPLOAD("SHOW_SHARING_SETTINGS_AFTER_UPLOAD"), - // If enabled, uses the v2 uploader (react implementation) for file entity uploads. - UPLOADER_V2("UPLOADER_V2"), - // If enabled, uses the file browser react implementation REACT_FILE_BROWSER("REACT_FILE_BROWSER"), diff --git a/src/main/java/org/sagebionetworks/web/client/GlobalApplicationStateImpl.java b/src/main/java/org/sagebionetworks/web/client/GlobalApplicationStateImpl.java index bfcac67bc9..67087654de 100644 --- a/src/main/java/org/sagebionetworks/web/client/GlobalApplicationStateImpl.java +++ b/src/main/java/org/sagebionetworks/web/client/GlobalApplicationStateImpl.java @@ -18,7 +18,11 @@ import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.datepicker.client.CalendarUtil; import com.google.inject.Inject; +import elemental2.dom.DomGlobal; +import elemental2.dom.DragEvent; +import elemental2.dom.EventListener; import elemental2.dom.FileList; +import elemental2.dom.HTMLDivElement; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -483,61 +487,61 @@ public void initializeToastContainer() { public void initializeDropZone() { if (!isDragDropInitialized) { isDragDropInitialized = true; - Element dropZoneElement = RootPanel.get("dropzone").getElement(); - Element rootPanelElement = RootPanel.get("rootPanel").getElement(); - _initializeDragDrop(this, dropZoneElement, rootPanelElement); + HTMLDivElement dropZoneElement = + (HTMLDivElement) DomGlobal.document.querySelector("[id=\"dropzone\"]"); + HTMLDivElement rootPanelElement = + (HTMLDivElement) DomGlobal.document.querySelector("[id=\"rootPanel\"]"); + initializeDragDrop(this, dropZoneElement, rootPanelElement); } } - private static final native void _initializeDragDrop( + private static void initializeDragDrop( GlobalApplicationStateImpl globalAppState, - Element dropZone, - Element rootPanel - ) /*-{ - try { - function showDropZone() { - dropZone.style.display = "block"; - } - - function hideDropZone() { - dropZone.style.display = "none"; - } - - $wnd - .addEventListener( - 'dragenter', - function(e) { - if (globalAppState.@org.sagebionetworks.web.client.GlobalApplicationStateImpl::isDragAndDropListenerSet()()) { - showDropZone(); - } - }); - - function allowDrag(e) { - e.dataTransfer.dropEffect = 'copy'; - e.preventDefault(); - } - - function handleDrop(e) { - e.preventDefault(); - hideDropZone(); - globalAppState.@org.sagebionetworks.web.client.GlobalApplicationStateImpl::onDrop(Lelemental2/dom/FileList;)(e.dataTransfer.files); - } - - dropZone.addEventListener('dragenter', allowDrag); - dropZone.addEventListener('dragover', allowDrag); - - dropZone.addEventListener('drop', handleDrop); - - //if files are dropped into the root panel, then ignore the event (do not open file contents if user does not have the upload dialog open). - rootPanel.addEventListener('drop', function(e) { - e.preventDefault(); - }); - rootPanel.addEventListener('dragenter', allowDrag); - rootPanel.addEventListener('dragover', allowDrag); - } catch (err) { - console.error(err); - } - }-*/; + HTMLDivElement dropZone, + HTMLDivElement rootPanel + ) { + try { + Runnable showDropZone = () -> dropZone.style.set("display", "block"); + Runnable hideDropZone = () -> dropZone.style.set("display", "none"); + + DomGlobal.window.addEventListener( + "dragenter", + e -> { + if (globalAppState.isDragAndDropListenerSet()) { + showDropZone.run(); + } + } + ); + + EventListener allowDrag = e -> { + if (e instanceof DragEvent) { + ((DragEvent) e).dataTransfer.dropEffect = "copy"; + e.preventDefault(); + } + }; + EventListener handleDrop = e -> { + if (e instanceof DragEvent) { + e.preventDefault(); + hideDropZone.run(); + globalAppState.onDrop(((DragEvent) e).dataTransfer.files); + } + }; + + dropZone.addEventListener("dragenter", allowDrag); + dropZone.addEventListener("dragover", allowDrag); + + dropZone.addEventListener("drop", handleDrop); + dropZone.addEventListener("dragend", e -> hideDropZone.run()); + dropZone.addEventListener("dragleave", e -> hideDropZone.run()); + + //if files are dropped into the root panel, then ignore the event (do not open file contents if user does not have the upload dialog open). + rootPanel.addEventListener("drop", elemental2.dom.Event::preventDefault); + rootPanel.addEventListener("dragenter", allowDrag); + rootPanel.addEventListener("dragover", allowDrag); + } catch (Exception e) { + DomGlobal.console.error("Error on drag-and-drop initialization", e); + } + } @Override public void setDropZoneHandler(CallbackP fileListCallback) { diff --git a/src/main/java/org/sagebionetworks/web/client/PortalGinInjector.java b/src/main/java/org/sagebionetworks/web/client/PortalGinInjector.java index 89b96cb5b9..54281a25c9 100644 --- a/src/main/java/org/sagebionetworks/web/client/PortalGinInjector.java +++ b/src/main/java/org/sagebionetworks/web/client/PortalGinInjector.java @@ -135,7 +135,6 @@ import org.sagebionetworks.web.client.widget.entity.controller.URLProvEntryView; import org.sagebionetworks.web.client.widget.entity.download.AddFolderDialogWidget; import org.sagebionetworks.web.client.widget.entity.download.QuizInfoDialog; -import org.sagebionetworks.web.client.widget.entity.download.UploadDialogWidget; import org.sagebionetworks.web.client.widget.entity.download.UploadDialogWidgetV2; import org.sagebionetworks.web.client.widget.entity.editor.APITableColumnConfigView; import org.sagebionetworks.web.client.widget.entity.editor.APITableConfigEditor; @@ -730,9 +729,7 @@ public interface PortalGinInjector extends Ginjector { EntityFinderWidgetView getEntityFinderWidgetView(); - UploadDialogWidget getUploadDialogWidget(); - - UploadDialogWidgetV2 getUploadDialogWidgetV2(); + UploadDialogWidgetV2 getUploadDialogWidget(); WikiMarkdownEditor getWikiMarkdownEditor(); diff --git a/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityUploadModalProps.java b/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityUploadModalProps.java index 783c8b7d92..7503c74613 100644 --- a/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityUploadModalProps.java +++ b/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityUploadModalProps.java @@ -1,6 +1,7 @@ package org.sagebionetworks.web.client.jsinterop; import jsinterop.annotations.JsFunction; +import jsinterop.annotations.JsNullable; import jsinterop.annotations.JsOverlay; import jsinterop.annotations.JsPackage; import jsinterop.annotations.JsType; @@ -20,6 +21,10 @@ public interface Callback { public Callback onClose; + @JsNullable + public Callback onUploadReady; + + @JsNullable public ReactRef ref; @JsOverlay @@ -27,13 +32,15 @@ public static EntityUploadModalProps create( String containerId, boolean open, Callback onClose, - ReactRef ref + ReactRef ref, + Callback onUploadReady ) { EntityUploadModalProps props = new EntityUploadModalProps(); props.entityId = containerId; props.open = open; props.onClose = onClose; props.ref = ref; + props.onUploadReady = onUploadReady; return props; } } diff --git a/src/main/java/org/sagebionetworks/web/client/jsinterop/ReactComponentProps.java b/src/main/java/org/sagebionetworks/web/client/jsinterop/ReactComponentProps.java index 84832af49a..38c20a5a2f 100644 --- a/src/main/java/org/sagebionetworks/web/client/jsinterop/ReactComponentProps.java +++ b/src/main/java/org/sagebionetworks/web/client/jsinterop/ReactComponentProps.java @@ -3,6 +3,7 @@ import com.google.gwt.dom.client.Element; import jsinterop.annotations.JsConstructor; import jsinterop.annotations.JsFunction; +import jsinterop.annotations.JsNullable; import jsinterop.annotations.JsPackage; import jsinterop.annotations.JsType; @@ -17,6 +18,10 @@ public interface CallbackRef { void run(Element element); } + @JsNullable + public String key; + // Either a ComponentRef or CallbackRef may be passed. A CallbackRef will be invoked when the ref is set. + @JsNullable public Object ref; } diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/controller/EntityActionControllerImpl.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/controller/EntityActionControllerImpl.java index cc08ffd2b6..42960a65ed 100755 --- a/src/main/java/org/sagebionetworks/web/client/widget/entity/controller/EntityActionControllerImpl.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/entity/controller/EntityActionControllerImpl.java @@ -40,7 +40,6 @@ import org.sagebionetworks.repo.model.Reference; import org.sagebionetworks.repo.model.RestrictableObjectType; import org.sagebionetworks.repo.model.RestrictionInformationResponse; -import org.sagebionetworks.repo.model.UserProfile; import org.sagebionetworks.repo.model.Versionable; import org.sagebionetworks.repo.model.VersionableEntity; import org.sagebionetworks.repo.model.auth.UserEntityPermissions; @@ -123,7 +122,6 @@ import org.sagebionetworks.web.client.widget.entity.act.ApproveUserAccessModal; import org.sagebionetworks.web.client.widget.entity.browse.EntityFinderWidget; import org.sagebionetworks.web.client.widget.entity.download.AddFolderDialogWidget; -import org.sagebionetworks.web.client.widget.entity.download.UploadDialogWidget; import org.sagebionetworks.web.client.widget.entity.download.UploadDialogWidgetV2; import org.sagebionetworks.web.client.widget.entity.file.AddToDownloadListV2; import org.sagebionetworks.web.client.widget.entity.menu.v3.Action; @@ -259,6 +257,7 @@ public class EntityActionControllerImpl EntityAccessControlListModalWidget entityAccessControlListModalWidget; RenameEntityModalWidget renameEntityModalWidget; EntityFinderWidget.Builder entityFinderBuilder; + UploadDialogWidgetV2 uploadDialogWidgetV2; EvaluationSubmitter submitter; EditFileMetadataModalWidget editFileMetadataModalWidget; EditProjectMetadataModalWidget editProjectMetadataModalWidget; @@ -545,16 +544,12 @@ private EvaluationSubmitter getEvaluationSubmitter() { return submitter; } - private UploadDialogWidget getNewUploadDialogWidget() { - UploadDialogWidget uploadDialogWidget = ginInjector.getUploadDialogWidget(); - view.setUploadDialogWidget(uploadDialogWidget.asWidget()); - return uploadDialogWidget; - } - - private UploadDialogWidgetV2 getNewUploadDialogWidgetV2() { - UploadDialogWidgetV2 uploadDialogWidgetV2 = - ginInjector.getUploadDialogWidgetV2(); - view.setUploadDialogWidget(uploadDialogWidgetV2.asWidget()); + private UploadDialogWidgetV2 getUploadDialogWidget() { + // Note: there must only be one UploadDialogWidget + if (uploadDialogWidgetV2 == null) { + uploadDialogWidgetV2 = ginInjector.getUploadDialogWidget(); + view.setUploadDialogWidget(uploadDialogWidgetV2.asWidget()); + } return uploadDialogWidgetV2; } @@ -619,6 +614,18 @@ public void configure( this.addToDownloadListWidget = addToDownloadListWidget; reconfigureActions(); + + // SWC-4693 - Always configure the upload dialog to support drag-n-drop from the files tab without opening the modal + configureUploader(); + } + + private void configureUploader() { + UploadDialogWidgetV2 uploadDialogWidgetV2 = getUploadDialogWidget(); + if (canUploadNewFileVersion() || canUploadFileToContainer()) { + uploadDialogWidgetV2.configure(entity.getId()); + } else { + uploadDialogWidgetV2.clearDragAndDropHandlers(); + } } private void reconfigureActions() { @@ -1340,28 +1347,31 @@ private void configureTableCommands() { } } + private boolean canUploadNewFileVersion() { + return ( + entityBundle.getEntity() instanceof FileEntity && + permissions.getCanCertifiedUserEdit() + ); + } + private void configureFileUpload() { - if (entityBundle.getEntity() instanceof FileEntity) { - actionMenu.setActionVisible( - Action.UPLOAD_NEW_FILE, - permissions.getCanCertifiedUserEdit() - ); - actionMenu.setActionListener(Action.UPLOAD_NEW_FILE, this); - } else { - actionMenu.setActionVisible(Action.UPLOAD_NEW_FILE, false); - } + actionMenu.setActionVisible( + Action.UPLOAD_NEW_FILE, + canUploadNewFileVersion() + ); + actionMenu.setActionListener(Action.UPLOAD_NEW_FILE, this); + } + + private boolean canUploadFileToContainer() { + return ( + isContainerOnFilesTab(entityBundle.getEntity(), currentArea) && + permissions.getCanCertifiedUserEdit() + ); } private void configureUploadNewFileEntity() { - if (isContainerOnFilesTab(entityBundle.getEntity(), currentArea)) { - actionMenu.setActionVisible( - Action.UPLOAD_FILE, - permissions.getCanCertifiedUserEdit() - ); - actionMenu.setActionListener(Action.UPLOAD_FILE, this); - } else { - actionMenu.setActionVisible(Action.UPLOAD_FILE, false); - } + actionMenu.setActionVisible(Action.UPLOAD_FILE, canUploadFileToContainer()); + actionMenu.setActionListener(Action.UPLOAD_FILE, this); } private void configureAddFolder() { @@ -1830,6 +1840,7 @@ public void onAction(Action action, ReactMouseEvent event) { onSubmit(); break; case UPLOAD_NEW_FILE: + case UPLOAD_FILE: onUploadFile(); break; case EDIT_PROVENANCE: @@ -1853,9 +1864,6 @@ public void onAction(Action action, ReactMouseEvent event) { case MANAGE_ACCESS_REQUIREMENTS: onManageAccessRequirements(); break; - case UPLOAD_FILE: - onUploadNewFileEntity(); - break; case CREATE_FOLDER: onCreateFolder(); break; @@ -2025,28 +2033,6 @@ private void postCheckCreateTableOrView(TableType table) { wizard.setOpen(true); } - private void onUploadNewFileEntity() { - checkUploadEntity(() -> { - if (featureFlagConfig.isFeatureEnabled(FeatureFlagKey.UPLOADER_V2)) { - UploadDialogWidgetV2 uploadDialogWidgetV2 = - getNewUploadDialogWidgetV2(); - uploadDialogWidgetV2.configure(entityBundle.getEntity().getId()); - uploadDialogWidgetV2.show(); - } else { - UploadDialogWidget uploader = getNewUploadDialogWidget(); - uploader.configure( - DisplayConstants.TEXT_UPLOAD_FILE_OR_LINK, - null, - entityBundle.getEntity().getId(), - null, - true - ); - uploader.setUploaderLinkNameVisible(true); - uploader.show(); - } - }); - } - private void onCreateFolder() { checkUploadEntity(() -> { AddFolderDialogWidget w = getAddFolderDialogWidget(); @@ -2101,29 +2087,11 @@ private void postEditProvenance() { } private void onUploadFile() { - checkUploadEntity(() -> { - postCheckUploadFile(); - }); + checkUploadEntity(this::postCheckUploadEntity); } - private void postCheckUploadFile() { - if (featureFlagConfig.isFeatureEnabled(FeatureFlagKey.UPLOADER_V2)) { - UploadDialogWidgetV2 uploadDialogWidgetV2 = getNewUploadDialogWidgetV2(); - uploadDialogWidgetV2.configure(entityBundle.getEntity().getId()); - uploadDialogWidgetV2.show(); - } else { - UploadDialogWidget uploadDialogWidget = getNewUploadDialogWidget(); - uploadDialogWidget.configure( - DisplayConstants.TEXT_UPLOAD_FILE_OR_LINK, - entityBundle.getEntity(), - null, - null, - true - ); - uploadDialogWidget.disableMultipleFileUploads(); - uploadDialogWidget.setUploaderLinkNameVisible(false); - uploadDialogWidget.show(); - } + private void postCheckUploadEntity() { + getUploadDialogWidget().show(); } private void onSubmit() { diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/download/UploadDialogWidget.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/download/UploadDialogWidget.java deleted file mode 100644 index 527f41c389..0000000000 --- a/src/main/java/org/sagebionetworks/web/client/widget/entity/download/UploadDialogWidget.java +++ /dev/null @@ -1,93 +0,0 @@ -package org.sagebionetworks.web.client.widget.entity.download; - -import com.google.gwt.event.shared.EventBus; -import com.google.gwt.user.client.ui.Widget; -import com.google.inject.Inject; -import org.sagebionetworks.repo.model.Entity; -import org.sagebionetworks.web.client.FeatureFlagConfig; -import org.sagebionetworks.web.client.FeatureFlagKey; -import org.sagebionetworks.web.client.events.EntityUpdatedEvent; -import org.sagebionetworks.web.client.utils.CallbackP; -import org.sagebionetworks.web.client.widget.SynapseWidgetPresenter; -import org.sagebionetworks.web.client.widget.sharing.EntityAccessControlListModalWidget; - -public class UploadDialogWidget - implements UploadDialogWidgetView.Presenter, SynapseWidgetPresenter { - - private UploadDialogWidgetView view; - private Uploader uploader; - private final EventBus eventBus; - private final EntityAccessControlListModalWidget entityAclEditor; - private final FeatureFlagConfig featureFlagConfig; - - @Inject - public UploadDialogWidget( - UploadDialogWidgetView view, - Uploader uploader, - EventBus eventBus, - EntityAccessControlListModalWidget entityAccessControlListModalWidget, - FeatureFlagConfig featureFlagConfig - ) { - this.view = view; - this.uploader = uploader; - this.eventBus = eventBus; - this.entityAclEditor = entityAccessControlListModalWidget; - this.featureFlagConfig = featureFlagConfig; - view.setPresenter(this); - } - - @Override - public Widget asWidget() { - return view.asWidget(); - } - - public void configure( - String title, - Entity entity, - String parentEntityId, - final CallbackP fileHandleIdCallback, - boolean isEntity - ) { - Widget body = uploader.configure( - entity, - parentEntityId, - fileHandleIdCallback, - isEntity - ); - view.configureDialog(title, body); - - // add handlers for closing the window - uploader.setSuccessHandler(benefactorId -> { - view.hideDialog(); - if ( - benefactorId != null && - featureFlagConfig.isFeatureEnabled( - FeatureFlagKey.SHOW_SHARING_SETTINGS_AFTER_UPLOAD - ) - ) { - entityAclEditor.configure( - benefactorId, - () -> eventBus.fireEvent(new EntityUpdatedEvent(benefactorId)), - true - ); - entityAclEditor.setOpen(true); - } - }); - - uploader.setCancelHandler(() -> { - view.hideDialog(); - }); - } - - public void disableMultipleFileUploads() { - uploader.disableMultipleFileUploads(); - } - - public void setUploaderLinkNameVisible(boolean visible) { - uploader.setUploaderLinkNameVisible(visible); - } - - public void show() { - view.showDialog(); - } -} diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/download/UploadDialogWidgetV2.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/download/UploadDialogWidgetV2.java index 400b99dc01..4dea3d053f 100644 --- a/src/main/java/org/sagebionetworks/web/client/widget/entity/download/UploadDialogWidgetV2.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/entity/download/UploadDialogWidgetV2.java @@ -3,6 +3,8 @@ import com.google.gwt.event.shared.EventBus; import com.google.gwt.user.client.ui.Widget; import com.google.inject.Inject; +import elemental2.dom.DomGlobal; +import elemental2.dom.FileList; import org.sagebionetworks.web.client.GlobalApplicationState; import org.sagebionetworks.web.client.context.SynapseReactClientFullContextPropsProvider; import org.sagebionetworks.web.client.events.EntityUpdatedEvent; @@ -18,6 +20,7 @@ public class UploadDialogWidgetV2 extends Widget { private final GlobalApplicationState globalApplicationState; private final EventBus eventBus; private final SynapseReactClientFullContextPropsProvider contextProvider; + private int keyCounter = 0; private final ReactComponent reactComponent; @@ -33,25 +36,30 @@ public UploadDialogWidgetV2( this.globalApplicationState = globalApplicationState; this.eventBus = eventBus; this.contextProvider = contextProvider; - this.reactComponent = new ReactComponent(); } public void configure(String entityId) { this.entityId = entityId; - globalApplicationState.setDropZoneHandler(fileList -> - this.ref.current.handleUploads(fileList) - ); - + this.ref = React.createRef(); renderComponent(false); } private void renderComponent(boolean open) { - this.ref = React.createRef(); + EntityUploadModalProps props = EntityUploadModalProps.create( + entityId, + open, + this::onClose, + this.ref, + this::onUploadReady + ); + + props.key = String.valueOf(keyCounter); + reactComponent.render( React.createElementWithSynapseContext( SRC.SynapseComponents.EntityUploadModal, - EntityUploadModalProps.create(entityId, open, this::onClose, this.ref), + props, contextProvider.getJsInteropContextProps() ) ); @@ -61,11 +69,33 @@ public void show() { renderComponent(true); } + private void handleDrop(FileList fileList) { + if (this.ref != null && this.ref.current != null) { + this.ref.current.handleUploads(fileList); + // Show the uploader + this.show(); + } else { + DomGlobal.console.error( + "EntityUploadHandle ref is null, aborting handleDrop" + ); + } + } + + private void onUploadReady() { + globalApplicationState.setDropZoneHandler(this::handleDrop); + } + private void onClose() { eventBus.fireEvent(new EntityUpdatedEvent(entityId)); + // Re-render the component with a new key to reset the state so it no longer shows the previous set of uploads + keyCounter++; renderComponent(false); } + public void clearDragAndDropHandlers() { + globalApplicationState.clearDropZoneHandler(); + } + @Override public Widget asWidget() { return reactComponent.asWidget(); @@ -73,7 +103,7 @@ public Widget asWidget() { @Override public void onUnload() { - globalApplicationState.clearDropZoneHandler(); + clearDragAndDropHandlers(); super.onUnload(); } diff --git a/src/test/java/org/sagebionetworks/web/unitclient/widget/entity/controller/EntityActionControllerImplTest.java b/src/test/java/org/sagebionetworks/web/unitclient/widget/entity/controller/EntityActionControllerImplTest.java index ff0e7994e0..5042bda362 100755 --- a/src/test/java/org/sagebionetworks/web/unitclient/widget/entity/controller/EntityActionControllerImplTest.java +++ b/src/test/java/org/sagebionetworks/web/unitclient/widget/entity/controller/EntityActionControllerImplTest.java @@ -42,10 +42,6 @@ import static org.sagebionetworks.web.client.widget.entity.controller.EntityActionControllerImpl.UPDATE_DOI_FOR; import static org.sagebionetworks.web.client.widget.entity.controller.EntityActionControllerImpl.WAS_SUCCESSFULLY_DELETED; import static org.sagebionetworks.web.client.widget.entity.controller.EntityActionControllerImpl.WIKI; -import static org.sagebionetworks.web.shared.WebConstants.FLAG_ISSUE_COLLECTOR_URL; -import static org.sagebionetworks.web.shared.WebConstants.FLAG_ISSUE_DESCRIPTION_PART_1; -import static org.sagebionetworks.web.shared.WebConstants.FLAG_ISSUE_PRIORITY; -import static org.sagebionetworks.web.shared.WebConstants.REVIEW_DATA_REQUEST_COMPONENT_ID; import com.google.gwt.event.shared.EventBus; import com.google.gwt.place.shared.Place; @@ -58,7 +54,6 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import org.apache.xpath.Arg; import org.gwtbootstrap3.extras.bootbox.client.callback.PromptCallback; import org.junit.Before; import org.junit.Test; @@ -114,7 +109,6 @@ import org.sagebionetworks.repo.model.wiki.WikiPage; import org.sagebionetworks.web.client.ChallengeClientAsync; import org.sagebionetworks.web.client.DisplayConstants; -import org.sagebionetworks.web.client.DisplayUtils; import org.sagebionetworks.web.client.DisplayUtils.NotificationVariant; import org.sagebionetworks.web.client.FeatureFlagConfig; import org.sagebionetworks.web.client.FeatureFlagKey; @@ -134,6 +128,7 @@ import org.sagebionetworks.web.client.events.DownloadListUpdatedEvent; import org.sagebionetworks.web.client.events.EntityUpdatedEvent; import org.sagebionetworks.web.client.jsinterop.CreateTableViewWizardProps; +import org.sagebionetworks.web.client.jsinterop.EntityUploadModalProps; import org.sagebionetworks.web.client.jsinterop.KeyFactory; import org.sagebionetworks.web.client.jsinterop.SqlDefinedTableEditorModalProps; import org.sagebionetworks.web.client.jsinterop.ToastMessageOptions; @@ -171,7 +166,7 @@ import org.sagebionetworks.web.client.widget.entity.controller.ProvenanceEditorWidget; import org.sagebionetworks.web.client.widget.entity.controller.StorageLocationWidget; import org.sagebionetworks.web.client.widget.entity.download.AddFolderDialogWidget; -import org.sagebionetworks.web.client.widget.entity.download.UploadDialogWidget; +import org.sagebionetworks.web.client.widget.entity.download.UploadDialogWidgetV2; import org.sagebionetworks.web.client.widget.entity.file.AddToDownloadListV2; import org.sagebionetworks.web.client.widget.entity.file.FileDownloadHandlerWidget; import org.sagebionetworks.web.client.widget.entity.menu.v3.Action; @@ -241,7 +236,7 @@ public class EntityActionControllerImplTest { EvaluationSubmitter mockSubmitter; @Mock - UploadDialogWidget mockUploader; + UploadDialogWidgetV2 mockUploader; @Mock EntityActionMenu mockActionMenu; @@ -423,6 +418,9 @@ public class EntityActionControllerImplTest { @Mock Element mockIconElement; + @Captor + ArgumentCaptor mockOnUploadModalReadyCaptor; + @Captor ArgumentCaptor< CreateTableViewWizardProps.OnComplete @@ -3762,6 +3760,11 @@ public void testOnUploadNewFileNoUpload() { @Test public void testOnUploadNewFileWithUpload() { + FileEntity fileEntity = new FileEntity(); + fileEntity.setId(entityId); + entityBundle.setEntity(fileEntity); + permissions.setCanCertifiedUserEdit(true); + entityBundle.setPermissions(permissions); AsyncMockStubber .callWithInvoke() .when(mockPreflightController) @@ -3775,8 +3778,8 @@ public void testOnUploadNewFileWithUpload() { mockAddToDownloadListWidget ); controller.onAction(Action.UPLOAD_NEW_FILE, null); + verify(mockUploader).configure(entityId); verify(mockUploader).show(); - verify(mockUploader).setUploaderLinkNameVisible(false); } @Test @@ -4516,18 +4519,8 @@ public void testUploadNewFileEntity() { mockAddToDownloadListWidget ); controller.onAction(Action.UPLOAD_FILE, null); - boolean isEntity = true; - Entity currentFileEntity = null; - CallbackP fileHandleIdCallback = null; - verify(mockUploader) - .configure( - DisplayConstants.TEXT_UPLOAD_FILE_OR_LINK, - currentFileEntity, - folderId, - fileHandleIdCallback, - isEntity - ); - verify(mockUploader).setUploaderLinkNameVisible(true); + + verify(mockUploader).configure(folderId); verify(mockUploader).show(); } @@ -5335,4 +5328,79 @@ public void testReportViolation() { WebConstants.PRIVACY_SECURITY_COMPLIANCE_HELP_CENTER_URL ); } + + @Test + public void testConfigureUploaderFile() { + FileEntity fileEntity = new FileEntity(); + fileEntity.setId(entityId); + entityBundle.setEntity(fileEntity); + + boolean canCertifiedUserEdit = true; + permissions.setCanCertifiedUserEdit(canCertifiedUserEdit); + entityBundle.setPermissions(permissions); + + currentEntityArea = EntityArea.FILES; + + controller.configure( + mockActionMenu, + entityBundle, + true, + wikiPageId, + currentEntityArea, + mockAddToDownloadListWidget + ); + + verify(mockUploader).configure(entityId); + verify(mockUploader, never()).clearDragAndDropHandlers(); + } + + @Test + public void testConfigureUploaderProject() { + Project project = new Project(); + project.setId(entityId); + entityBundle.setEntity(project); + + boolean canCertifiedUserEdit = true; + permissions.setCanCertifiedUserEdit(canCertifiedUserEdit); + entityBundle.setPermissions(permissions); + + currentEntityArea = EntityArea.FILES; + + controller.configure( + mockActionMenu, + entityBundle, + true, + wikiPageId, + currentEntityArea, + mockAddToDownloadListWidget + ); + + verify(mockUploader).configure(entityId); + verify(mockUploader, never()).clearDragAndDropHandlers(); + } + + @Test + public void testConfigureUploaderProjectNotFilesTab() { + Project project = new Project(); + project.setId(entityId); + entityBundle.setEntity(project); + + boolean canCertifiedUserEdit = true; + permissions.setCanCertifiedUserEdit(canCertifiedUserEdit); + entityBundle.setPermissions(permissions); + + currentEntityArea = EntityArea.WIKI; + + controller.configure( + mockActionMenu, + entityBundle, + true, + wikiPageId, + currentEntityArea, + mockAddToDownloadListWidget + ); + + verify(mockUploader, never()).configure(entityId); + verify(mockUploader).clearDragAndDropHandlers(); + } } diff --git a/src/test/java/org/sagebionetworks/web/unitclient/widget/entity/download/UploadDialogTest.java b/src/test/java/org/sagebionetworks/web/unitclient/widget/entity/download/UploadDialogTest.java deleted file mode 100644 index 5c2fe4316e..0000000000 --- a/src/test/java/org/sagebionetworks/web/unitclient/widget/entity/download/UploadDialogTest.java +++ /dev/null @@ -1,166 +0,0 @@ -package org.sagebionetworks.web.unitclient.widget.entity.download; - -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import com.google.gwt.event.shared.EventBus; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnitRunner; -import org.sagebionetworks.repo.model.Entity; -import org.sagebionetworks.web.client.FeatureFlagConfig; -import org.sagebionetworks.web.client.FeatureFlagKey; -import org.sagebionetworks.web.client.events.CancelHandler; -import org.sagebionetworks.web.client.events.UploadSuccessHandler; -import org.sagebionetworks.web.client.jsinterop.EntityAclEditorModalProps; -import org.sagebionetworks.web.client.utils.CallbackP; -import org.sagebionetworks.web.client.widget.entity.download.UploadDialogWidget; -import org.sagebionetworks.web.client.widget.entity.download.UploadDialogWidgetView; -import org.sagebionetworks.web.client.widget.entity.download.Uploader; -import org.sagebionetworks.web.client.widget.sharing.EntityAccessControlListModalWidget; - -@RunWith(MockitoJUnitRunner.Silent.class) -public class UploadDialogTest { - - @Mock - UploadDialogWidgetView view; - - @Mock - Uploader mockUploader; - - @Mock - EventBus mockEventBus; - - @Mock - EntityAccessControlListModalWidget mockEntityAccessControlListModalWidget; - - @Mock - FeatureFlagConfig mockFeatureFlagConfig; - - @Captor - ArgumentCaptor uploadSuccessCaptor; - - @Captor - ArgumentCaptor< - EntityAclEditorModalProps.Callback - > updateAclSuccessCallbackCaptor; - - UploadDialogWidget widget; - - @Before - public void before() throws Exception { - widget = - new UploadDialogWidget( - view, - mockUploader, - mockEventBus, - mockEntityAccessControlListModalWidget, - mockFeatureFlagConfig - ); - } - - @Test - public void testConfigure() { - when( - mockFeatureFlagConfig.isFeatureEnabled( - FeatureFlagKey.SHOW_SHARING_SETTINGS_AFTER_UPLOAD - ) - ) - .thenReturn(false); - - String title = "dialog title"; - Entity entity = mock(Entity.class); - String parentEntityId = "parent"; - CallbackP fileHandleIdCallback = mock(CallbackP.class); - boolean isEntity = true; - widget.configure( - title, - entity, - parentEntityId, - fileHandleIdCallback, - isEntity - ); - - verify(mockUploader) - .configure(entity, parentEntityId, fileHandleIdCallback, isEntity); - verify(view).configureDialog(eq(title), any()); - - verify(mockUploader).setSuccessHandler(uploadSuccessCaptor.capture()); - verify(mockUploader).setCancelHandler(any(CancelHandler.class)); - - // simulate a successful upload - String benefactorId = "syn123"; - uploadSuccessCaptor.getValue().onSuccessfulUpload(benefactorId); - verify(view).hideDialog(); - verify(mockEntityAccessControlListModalWidget, never()) - .configure(eq(benefactorId), any(), anyBoolean()); - verify(mockEntityAccessControlListModalWidget, never()).setOpen(true); - } - - @Test - public void testSharingSettingsFeatureEnabled() { - when( - mockFeatureFlagConfig.isFeatureEnabled( - FeatureFlagKey.SHOW_SHARING_SETTINGS_AFTER_UPLOAD - ) - ) - .thenReturn(true); - - String title = "dialog title"; - Entity entity = mock(Entity.class); - String parentEntityId = "parent"; - CallbackP fileHandleIdCallback = mock(CallbackP.class); - boolean isEntity = true; - widget.configure( - title, - entity, - parentEntityId, - fileHandleIdCallback, - isEntity - ); - - verify(mockUploader) - .configure(entity, parentEntityId, fileHandleIdCallback, isEntity); - verify(view).configureDialog(eq(title), any()); - - verify(mockUploader).setSuccessHandler(uploadSuccessCaptor.capture()); - verify(mockUploader).setCancelHandler(any(CancelHandler.class)); - - // simulate a successful upload - String benefactorId = "syn123"; - uploadSuccessCaptor.getValue().onSuccessfulUpload(benefactorId); - verify(view).hideDialog(); - verify(mockEntityAccessControlListModalWidget) - .configure( - eq(benefactorId), - updateAclSuccessCallbackCaptor.capture(), - eq(true) - ); - verify(mockEntityAccessControlListModalWidget).setOpen(true); - - // Simulate a successful ACL save - updateAclSuccessCallbackCaptor.getValue().run(); - verify(mockEventBus).fireEvent(any()); - } - - @Test - public void testDisableMultipleFileUploads() { - widget.disableMultipleFileUploads(); - verify(mockUploader).disableMultipleFileUploads(); - } - - @Test - public void testShow() { - widget.show(); - verify(view).showDialog(); - } -} From 9e3857a10a80a7c252782c49cf04dd4904f7b8d5 Mon Sep 17 00:00:00 2001 From: Nick Grosenbacher Date: Thu, 9 Jan 2025 12:07:59 -0500 Subject: [PATCH 2/2] Remove comment --- .../widget/entity/controller/EntityActionControllerImpl.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/controller/EntityActionControllerImpl.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/controller/EntityActionControllerImpl.java index 42960a65ed..13fc29402e 100755 --- a/src/main/java/org/sagebionetworks/web/client/widget/entity/controller/EntityActionControllerImpl.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/entity/controller/EntityActionControllerImpl.java @@ -545,7 +545,6 @@ private EvaluationSubmitter getEvaluationSubmitter() { } private UploadDialogWidgetV2 getUploadDialogWidget() { - // Note: there must only be one UploadDialogWidget if (uploadDialogWidgetV2 == null) { uploadDialogWidgetV2 = ginInjector.getUploadDialogWidget(); view.setUploadDialogWidget(uploadDialogWidgetV2.asWidget());