From bb329514bf8880de9459c75a8059d406e711b28d Mon Sep 17 00:00:00 2001 From: Jin Jun Oh Date: Wed, 28 Feb 2024 14:42:23 -0800 Subject: [PATCH 1/2] SWC-6669: migrate legacy EntityViewScopeEditor to react component --- .../web/client/PortalGinModule.java | 4 + .../EntityViewScopeEditorModalProps.java | 44 ++++ .../web/client/jsinterop/SRC.java | 1 + .../EntityViewScopeEditorModalWidget.java | 70 ++++++ .../EntityViewScopeEditorModalWidgetView.java | 8 + ...ityViewScopeEditorModalWidgetViewImpl.java | 41 ++++ .../modal/fileview/EntityViewScopeWidget.java | 97 ++------- .../fileview/EntityViewScopeWidgetView.java | 14 +- .../EntityViewScopeWidgetViewImpl.java | 53 +---- .../EntityViewScopeWidgetViewImpl.ui.xml | 40 +--- .../EntityViewScopeEditorModalWidgetTest.java | 84 ++++++++ .../table/modal/fileview/ScopeWidgetTest.java | 203 ++++++------------ 12 files changed, 344 insertions(+), 315 deletions(-) create mode 100644 src/main/java/org/sagebionetworks/web/client/jsinterop/EntityViewScopeEditorModalProps.java create mode 100644 src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidget.java create mode 100644 src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetView.java create mode 100644 src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetViewImpl.java create mode 100644 src/test/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetTest.java diff --git a/src/main/java/org/sagebionetworks/web/client/PortalGinModule.java b/src/main/java/org/sagebionetworks/web/client/PortalGinModule.java index d41eebe16c..64f38d7ff1 100644 --- a/src/main/java/org/sagebionetworks/web/client/PortalGinModule.java +++ b/src/main/java/org/sagebionetworks/web/client/PortalGinModule.java @@ -271,6 +271,8 @@ import org.sagebionetworks.web.client.widget.entity.EntityPageTopViewImpl; import org.sagebionetworks.web.client.widget.entity.EntitySearchBoxView; import org.sagebionetworks.web.client.widget.entity.EntitySearchBoxViewImpl; +import org.sagebionetworks.web.client.widget.entity.EntityViewScopeEditorModalWidgetView; +import org.sagebionetworks.web.client.widget.entity.EntityViewScopeEditorModalWidgetViewImpl; import org.sagebionetworks.web.client.widget.entity.FavoriteWidgetView; import org.sagebionetworks.web.client.widget.entity.FavoriteWidgetViewImpl; import org.sagebionetworks.web.client.widget.entity.MarkdownEditorWidgetView; @@ -1446,6 +1448,8 @@ protected void configure() { bind(FileDownloadMenuItemView.class).to(FileDownloadMenuItemViewImpl.class); bind(SqlDefinedEditorModalWidgetView.class) .to(SqlDefinedEditorModalWidgetViewImpl.class); + bind(EntityViewScopeEditorModalWidgetView.class) + .to(EntityViewScopeEditorModalWidgetViewImpl.class); bind(ChallengeWidgetView.class).to(ChallengeWidgetViewImpl.class); bind(SelectTeamModalView.class).to(SelectTeamModalViewImpl.class); bind(ApproveUserAccessModalView.class) diff --git a/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityViewScopeEditorModalProps.java b/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityViewScopeEditorModalProps.java new file mode 100644 index 0000000000..b16c97d8a6 --- /dev/null +++ b/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityViewScopeEditorModalProps.java @@ -0,0 +1,44 @@ +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; + +@JsType(isNative = true, namespace = JsPackage.GLOBAL, name = "Object") +public class EntityViewScopeEditorModalProps extends ReactComponentProps { + + @FunctionalInterface + @JsFunction + public interface Callback { + void run(); + } + + public String entityId; + + @JsNullable + public Callback onUpdate; + + @JsNullable + public Callback onCancel; + + public boolean open; + + @JsOverlay + public static EntityViewScopeEditorModalProps create( + String entityId, + Callback onUpdate, + Callback onCancel, + boolean open + ) { + EntityViewScopeEditorModalProps props = + new EntityViewScopeEditorModalProps(); + props.entityId = entityId; + props.onUpdate = onUpdate; + props.onCancel = onCancel; + props.open = open; + return props; + } +} +// TODO: create EntityViewScopeEditorModalWidget, View, and IMPL diff --git a/src/main/java/org/sagebionetworks/web/client/jsinterop/SRC.java b/src/main/java/org/sagebionetworks/web/client/jsinterop/SRC.java index 1dc498a877..d38fd473c0 100644 --- a/src/main/java/org/sagebionetworks/web/client/jsinterop/SRC.java +++ b/src/main/java/org/sagebionetworks/web/client/jsinterop/SRC.java @@ -66,6 +66,7 @@ public static class SynapseComponents { public static ReactComponentType AccessRequirementRelatedProjectsList; public static ReactComponentType CreateTableViewWizard; public static ReactComponentType SqlDefinedTableEditorModal; + public static ReactComponentType EntityViewScopeEditorModal; /** * Pushes a global toast message. In SWC, you should use {@link DisplayUtils#notify}, rather than calling this method directly. diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidget.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidget.java new file mode 100644 index 0000000000..3c04b62b67 --- /dev/null +++ b/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidget.java @@ -0,0 +1,70 @@ +package org.sagebionetworks.web.client.widget.entity; + +import com.google.gwt.user.client.ui.IsWidget; +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; +import java.util.ArrayList; +import java.util.List; +import org.sagebionetworks.repo.model.Reference; +import org.sagebionetworks.web.client.GlobalApplicationState; +import org.sagebionetworks.web.client.jsinterop.EntityViewScopeEditorModalProps; +import org.sagebionetworks.web.client.jsinterop.SqlDefinedTableEditorModalProps; +import org.sagebionetworks.web.client.widget.table.modal.fileview.TableType; + +public class EntityViewScopeEditorModalWidget implements IsWidget { + + private final GlobalApplicationState globalApplicationState; + private final EntityViewScopeEditorModalWidgetView view; + + private String entityId; + private EntityViewScopeEditorModalProps.Callback onCancel; + private EntityViewScopeEditorModalProps.Callback onUpdate; + boolean open; + + @Inject + public EntityViewScopeEditorModalWidget( + EntityViewScopeEditorModalWidgetView view, + GlobalApplicationState globalApplicationState + ) { + super(); + this.view = view; + this.globalApplicationState = globalApplicationState; + } + + public void configure( + String entityId, + EntityViewScopeEditorModalProps.Callback onUpdate, + EntityViewScopeEditorModalProps.Callback onCancel, + boolean open + ) { + this.entityId = entityId; + this.onUpdate = onUpdate; + this.onCancel = onCancel; + this.open = open; + EntityViewScopeEditorModalProps props = + EntityViewScopeEditorModalProps.create( + entityId, + onUpdate, + onCancel, + open + ); + view.renderComponent(props); + } + + public void setOpen(boolean open) { + globalApplicationState.setIsEditing(open); + EntityViewScopeEditorModalProps props = + EntityViewScopeEditorModalProps.create( + entityId, + onUpdate, + onCancel, + open + ); + view.renderComponent(props); + } + + @Override + public Widget asWidget() { + return view.asWidget(); + } +} diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetView.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetView.java new file mode 100644 index 0000000000..b6a38f731d --- /dev/null +++ b/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetView.java @@ -0,0 +1,8 @@ +package org.sagebionetworks.web.client.widget.entity; + +import com.google.gwt.user.client.ui.IsWidget; +import org.sagebionetworks.web.client.jsinterop.EntityViewScopeEditorModalProps; + +public interface EntityViewScopeEditorModalWidgetView extends IsWidget { + void renderComponent(EntityViewScopeEditorModalProps props); +} diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetViewImpl.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetViewImpl.java new file mode 100644 index 0000000000..cb6d6e4638 --- /dev/null +++ b/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetViewImpl.java @@ -0,0 +1,41 @@ +package org.sagebionetworks.web.client.widget.entity; + +import com.google.gwt.user.client.ui.Widget; +import com.google.inject.Inject; +import org.sagebionetworks.web.client.context.SynapseReactClientFullContextPropsProvider; +import org.sagebionetworks.web.client.jsinterop.EntityViewScopeEditorModalProps; +import org.sagebionetworks.web.client.jsinterop.React; +import org.sagebionetworks.web.client.jsinterop.ReactNode; +import org.sagebionetworks.web.client.jsinterop.SRC; +import org.sagebionetworks.web.client.widget.ReactComponentDiv; + +public class EntityViewScopeEditorModalWidgetViewImpl + implements EntityViewScopeEditorModalWidgetView { + + private final SynapseReactClientFullContextPropsProvider propsProvider; + private final ReactComponentDiv reactComponentDiv; + + @Inject + public EntityViewScopeEditorModalWidgetViewImpl( + SynapseReactClientFullContextPropsProvider propsProvider + ) { + super(); + this.propsProvider = propsProvider; + reactComponentDiv = new ReactComponentDiv(); + } + + @Override + public void renderComponent(EntityViewScopeEditorModalProps props) { + ReactNode reactNode = React.createElementWithSynapseContext( + SRC.SynapseComponents.EntityViewScopeEditorModal, + props, + propsProvider.getJsInteropContextProps() + ); + reactComponentDiv.render(reactNode); + } + + @Override + public Widget asWidget() { + return reactComponentDiv.asWidget(); + } +} diff --git a/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidget.java b/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidget.java index 6e19f1ecf8..2b5f68e67d 100644 --- a/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidget.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidget.java @@ -15,6 +15,7 @@ import org.sagebionetworks.web.client.SynapseJavascriptClient; import org.sagebionetworks.web.client.events.EntityUpdatedEvent; import org.sagebionetworks.web.client.widget.SynapseWidgetPresenter; +import org.sagebionetworks.web.client.widget.entity.EntityViewScopeEditorModalWidget; import org.sagebionetworks.web.client.widget.entity.controller.SynapseAlert; /** @@ -40,8 +41,8 @@ public class EntityViewScopeWidget EntityViewScopeWidgetView view; SynapseJavascriptClient jsClient; EntityBundle bundle; - EntityContainerListWidget viewScopeWidget, editScopeWidget; - SynapseAlert synAlert; + EntityContainerListWidget viewScopeWidget; + EntityViewScopeEditorModalWidget editEntityViewScopeModalWidget; // TODO: replace edit scope widget with the react compoenent widget & fix corresponding test EntityView currentView; TableType tableType; EventBus eventBus; @@ -56,20 +57,19 @@ public EntityViewScopeWidget( EntityViewScopeWidgetView view, SynapseJavascriptClient jsClient, EntityContainerListWidget viewScopeWidget, - EntityContainerListWidget editScopeWidget, - SynapseAlert synAlert, + EntityViewScopeEditorModalWidget editEntityViewScopeModalWidget, EventBus eventBus ) { this.jsClient = jsClient; this.view = view; this.viewScopeWidget = viewScopeWidget; - this.editScopeWidget = editScopeWidget; - this.synAlert = synAlert; + this.editEntityViewScopeModalWidget = editEntityViewScopeModalWidget; this.eventBus = eventBus; view.setPresenter(this); - view.setEditableEntityListWidget(editScopeWidget.asWidget()); + view.setEditableEntityViewModalWidget( + editEntityViewScopeModalWidget.asWidget() + ); view.setEntityListWidget(viewScopeWidget.asWidget()); - view.setSynAlert(synAlert.asWidget()); } private List getReferencesFromIdList(List ids) { @@ -105,22 +105,6 @@ public void configure(EntityBundle bundle, boolean isEditable) { view.setVisible(isVisible); } - private static boolean isEditMaskSupportedInWebClient(TableType tableType) { - if (tableType.getViewTypeMask() == PROJECT) { - // Masks of project Views are not editable - return false; - } else { - // If the entity view isn't a project view, then it can only have any combination of File | Folder | Table | Dataset - // If it contains any other type, it's not editable because the editor doesn't display all of the fields required for the user to update this mask. - return !( - tableType.isIncludeEntityView() || - tableType.isIncludeSubmissionView() || - tableType.isIncludeDockerRepo() || - tableType.isIncludeProject() - ); - } - } - @Override public Widget asWidget() { return view.asWidget(); @@ -137,61 +121,20 @@ public void updateViewTypeMask() { ); } - @Override - public void onSave() { - // update scope - synAlert.clear(); - view.setLoading(true); - currentView.setScopeIds(editScopeWidget.getEntityIds()); - currentView.setViewTypeMask(tableType.getViewTypeMask().longValue()); - currentView.setType(null); - jsClient.updateEntity( - currentView, - null, - null, - new AsyncCallback() { - @Override - public void onSuccess(Entity entity) { - view.setLoading(false); - view.hideModal(); - eventBus.fireEvent(new EntityUpdatedEvent(entity.getId())); - } - - @Override - public void onFailure(Throwable caught) { - view.setLoading(false); - synAlert.handleException(caught); - } - } - ); - } - @Override public void onEditScopeAndMask() { - List references = getReferencesFromIdList( - currentView.getScopeIds() + String entityId = currentView.getId(); + editEntityViewScopeModalWidget.configure( + entityId, + () -> { + editEntityViewScopeModalWidget.setOpen(false); + eventBus.fireEvent(new EntityUpdatedEvent(currentView.getId())); + }, + () -> { + editEntityViewScopeModalWidget.setOpen(false); + }, + true ); - // configure edit list, and show modal - editScopeWidget.configure(references, true, tableType); - - // The mask may not be editable since not all masks are supported in the web client - boolean isMaskEditable = - isEditable && isEditMaskSupportedInWebClient(tableType); - if (!isMaskEditable) { - synAlert.consoleError( - "View type mask is not supported by web client, blocking edit. Mask value:" + - ((EntityView) currentView).getViewTypeMask() - ); - } - - view.setEditMaskVisible(isMaskEditable); - if (isMaskEditable) { - // update the checkbox state based on the view type mask - view.setIsFileSelected(tableType.isIncludeFiles()); - view.setIsFolderSelected(tableType.isIncludeFolders()); - view.setIsTableSelected(tableType.isIncludeTables()); - view.setIsDatasetSelected(tableType.isIncludeDatasets()); - } - view.showModal(); + editEntityViewScopeModalWidget.setOpen(true); } } diff --git a/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetView.java b/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetView.java index 552cb8d5dd..111f2abaec 100644 --- a/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetView.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetView.java @@ -13,20 +13,10 @@ public interface EntityViewScopeWidgetView extends IsWidget { void setEntityListWidget(IsWidget w); - void setEditableEntityListWidget(IsWidget w); - - void setSynAlert(IsWidget w); - - void showModal(); - - void hideModal(); + void setEditableEntityViewModalWidget(IsWidget w); // TODO: replace setEditableEntityViewModalWidget void setEditMaskAndScopeButtonVisible(boolean visible); - void setEditMaskVisible(boolean visible); - - void setLoading(boolean loading); - boolean isFileSelected(); void setIsFileSelected(boolean selected); @@ -44,8 +34,6 @@ public interface EntityViewScopeWidgetView extends IsWidget { void setIsDatasetSelected(boolean selected); public interface Presenter { - void onSave(); - void onEditScopeAndMask(); void updateViewTypeMask(); diff --git a/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetViewImpl.java b/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetViewImpl.java index 74f03b902f..4d463ed0f6 100644 --- a/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetViewImpl.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetViewImpl.java @@ -11,7 +11,9 @@ import org.gwtbootstrap3.client.ui.Button; import org.gwtbootstrap3.client.ui.Modal; import org.gwtbootstrap3.client.ui.html.Div; +import org.gwtbootstrap3.client.ui.html.Span; import org.sagebionetworks.web.client.DisplayUtils; +import org.sagebionetworks.web.client.PortalGinInjector; public class EntityViewScopeWidgetViewImpl implements EntityViewScopeWidgetView { @@ -25,21 +27,9 @@ public interface Binder @UiField SimplePanel editScopeContainer; - @UiField - SimplePanel editScopeAlertContainer; - - @UiField - Button saveButton; - @UiField Button editButton; - @UiField - Modal editModal; - - @UiField - Div viewOptionsContainer; - Widget widget; Presenter presenter; FileViewOptions viewOptions; @@ -52,7 +42,6 @@ public EntityViewScopeWidgetViewImpl( ) { widget = binder.createAndBindUi(this); this.viewOptions = viewOptions; - viewOptionsContainer.add(viewOptions); editButton.addClickHandler( new ClickHandler() { @Override @@ -61,18 +50,9 @@ public void onClick(ClickEvent event) { } } ); - saveButton.addClickHandler( - new ClickHandler() { - @Override - public void onClick(ClickEvent event) { - presenter.onSave(); - } - } - ); viewOptions.addClickHandler(event -> { presenter.updateViewTypeMask(); }); - originalButtonText = saveButton.getText(); } @Override @@ -91,28 +71,11 @@ public void setEntityListWidget(IsWidget entityListWidget) { viewScopeContainer.setWidget(entityListWidget); } - @Override - public void setEditableEntityListWidget(IsWidget entityListWidget) { + public void setEditableEntityViewModalWidget(IsWidget entityListWidget) { editScopeContainer.clear(); editScopeContainer.setWidget(entityListWidget); } - @Override - public void showModal() { - editModal.show(); - } - - @Override - public void hideModal() { - editModal.hide(); - } - - @Override - public void setSynAlert(IsWidget w) { - editScopeAlertContainer.clear(); - editScopeAlertContainer.setWidget(w); - } - @Override public void setPresenter(Presenter presenter) { this.presenter = presenter; @@ -123,16 +86,6 @@ public void setEditMaskAndScopeButtonVisible(boolean visible) { editButton.setVisible(visible); } - @Override - public void setEditMaskVisible(boolean visible) { - viewOptionsContainer.setVisible(visible); - } - - @Override - public void setLoading(boolean loading) { - DisplayUtils.showLoading(saveButton, loading, originalButtonText); - } - @Override public boolean isFileSelected() { return viewOptions.isIncludeFiles(); diff --git a/src/main/resources/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetViewImpl.ui.xml b/src/main/resources/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetViewImpl.ui.xml index fc6277d938..4591bdc207 100755 --- a/src/main/resources/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetViewImpl.ui.xml +++ b/src/main/resources/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidgetViewImpl.ui.xml @@ -12,6 +12,7 @@ > + - - - - - - - - Find containers to include in the View scope - - - - - - - Save - - - Cancel - - - diff --git a/src/test/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetTest.java b/src/test/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetTest.java new file mode 100644 index 0000000000..8d9bedb1e1 --- /dev/null +++ b/src/test/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetTest.java @@ -0,0 +1,84 @@ +package org.sagebionetworks.web.client.widget.entity; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.junit.After; +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.runners.MockitoJUnitRunner; +import org.sagebionetworks.web.client.GlobalApplicationState; +import org.sagebionetworks.web.client.PlaceChanger; +import org.sagebionetworks.web.client.jsinterop.EntityViewScopeEditorModalProps; + +@RunWith(MockitoJUnitRunner.class) +public class EntityViewScopeEditorModalWidgetTest { + + @Mock + EntityViewScopeEditorModalWidgetView mockView; + + @Mock + EntityViewScopeEditorModalProps.Callback mockOnUpdate; + + @Mock + EntityViewScopeEditorModalProps.Callback mockOnCancel; + + @Mock + GlobalApplicationState mockGlobalAppState; + + @Mock + PlaceChanger mockPlaceChanger; + + @Captor + ArgumentCaptor propsCaptor; + + EntityViewScopeEditorModalWidget widget; + + public static final String ENTITY_ID = "syn123"; + public static final boolean open = true; + + @Before + public void before() { + widget = new EntityViewScopeEditorModalWidget(mockView, mockGlobalAppState); + when(mockGlobalAppState.getPlaceChanger()).thenReturn(mockPlaceChanger); + } + + @After + public void validate() { + validateMockitoUsage(); + } + + @Test + public void testConstruction() { + widget.configure(ENTITY_ID, mockOnUpdate, mockOnCancel, open); + verify(mockView).renderComponent(propsCaptor.capture()); + EntityViewScopeEditorModalProps capturedProps = propsCaptor.getValue(); + + assertEquals(ENTITY_ID, capturedProps.entityId); + assertEquals(mockOnUpdate, capturedProps.onUpdate); + assertEquals(mockOnCancel, capturedProps.onCancel); + assertEquals(open, capturedProps.open); + } + + @Test + public void testSetOpen() { + widget.setOpen(true); + verify(mockGlobalAppState).setIsEditing(true); + verify(mockView).renderComponent(propsCaptor.capture()); + assertTrue(propsCaptor.getValue().open); + widget.setOpen(false); + verify(mockGlobalAppState).setIsEditing(false); + verify(mockView, times(2)).renderComponent(propsCaptor.capture()); + assertFalse(propsCaptor.getValue().open); + } + + @Test + public void testAsWidget() { + widget.asWidget(); + verify(mockView).asWidget(); + } +} diff --git a/src/test/java/org/sagebionetworks/web/unitclient/widget/table/modal/fileview/ScopeWidgetTest.java b/src/test/java/org/sagebionetworks/web/unitclient/widget/table/modal/fileview/ScopeWidgetTest.java index e783138f51..13c53c9621 100644 --- a/src/test/java/org/sagebionetworks/web/unitclient/widget/table/modal/fileview/ScopeWidgetTest.java +++ b/src/test/java/org/sagebionetworks/web/unitclient/widget/table/modal/fileview/ScopeWidgetTest.java @@ -1,9 +1,6 @@ package org.sagebionetworks.web.unitclient.widget.table.modal.fileview; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.never; +import static org.mockito.Matchers.*; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -16,6 +13,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.runners.MockitoJUnitRunner; @@ -24,10 +22,10 @@ import org.sagebionetworks.repo.model.table.EntityView; import org.sagebionetworks.repo.model.table.Table; import org.sagebionetworks.repo.model.table.ViewType; -import org.sagebionetworks.repo.model.table.ViewTypeMask; import org.sagebionetworks.web.client.SynapseJavascriptClient; import org.sagebionetworks.web.client.events.EntityUpdatedEvent; -import org.sagebionetworks.web.client.widget.entity.controller.SynapseAlert; +import org.sagebionetworks.web.client.jsinterop.EntityViewScopeEditorModalProps; +import org.sagebionetworks.web.client.widget.entity.EntityViewScopeEditorModalWidget; import org.sagebionetworks.web.client.widget.table.modal.fileview.EntityContainerListWidget; import org.sagebionetworks.web.client.widget.table.modal.fileview.EntityViewScopeWidget; import org.sagebionetworks.web.client.widget.table.modal.fileview.EntityViewScopeWidgetView; @@ -44,14 +42,11 @@ public class ScopeWidgetTest { @Mock SynapseJavascriptClient mockJsClient; - @Mock - SynapseAlert mockSynapseAlert; - @Mock EntityContainerListWidget mockViewScopeWidget; @Mock - EntityContainerListWidget mockEditScopeWidget; + EntityViewScopeEditorModalWidget mockEntityViewScopeEditorModalWidget; @Mock EntityBundle mockBundle; @@ -76,6 +71,8 @@ public class ScopeWidgetTest { String scopeId1 = "syn456"; String scopeId2 = "syn789"; + String entityId = "syn123"; + // Versions for Dataset only Long scopeVersion1 = 5L; Long scopeVersion2 = 2L; @@ -92,12 +89,11 @@ public void before() { mockView, mockJsClient, mockViewScopeWidget, - mockEditScopeWidget, - mockSynapseAlert, + mockEntityViewScopeEditorModalWidget, mockEventBus ); when(mockBundle.getEntity()).thenReturn(mockEntityView); - when(mockEntityView.getId()).thenReturn("syn123"); + when(mockEntityView.getId()).thenReturn(entityId); when(mockEntityView.getScopeIds()).thenReturn(mockScopeIds); when(mockEntityView.getType()).thenReturn(ViewType.file); when(mockEntityView.getViewTypeMask()).thenReturn(null); @@ -137,13 +133,12 @@ public void before() { @Test public void testConstruction() { verify(mockView).setPresenter(widget); - verify(mockView).setEditableEntityListWidget(any(Widget.class)); + verify(mockView).setEditableEntityViewModalWidget(any(Widget.class)); verify(mockView).setEntityListWidget(any(Widget.class)); - verify(mockView).setSynAlert(any(Widget.class)); } @Test - public void testConfigureEntityViewHappyCase() { + public void testOnEditScopeAndMaskOnUpdate() { // configure with an entityview, edit the scope, and save. boolean isEditable = true; widget.configure(mockBundle, isEditable); @@ -155,41 +150,54 @@ public void testConfigureEntityViewHappyCase() { verify(mockView).setEditMaskAndScopeButtonVisible(true); verify(mockView).setVisible(true); - // edit widget.onEditScopeAndMask(); - verify(mockEditScopeWidget) - .configure(mockReferencesWithoutVersions, true, TableType.file_view); - verify(mockView).showModal(); - - // update file view to file+table view - when(mockView.isFileSelected()).thenReturn(true); - when(mockView.isTableSelected()).thenReturn(true); - widget.updateViewTypeMask(); - - // save new scope - widget.onSave(); - - verify(mockSynapseAlert).clear(); - verify(mockView).setLoading(true); - // verify view type has been updated - // clears out old ViewType, replaced with mask - verify(mockEntityView).setType(null); - verify(mockEntityView) - .setViewTypeMask( - ViewTypeMask.getMaskForDepricatedType(ViewType.file_and_table) - ); - verify(mockJsClient) - .updateEntity( - any(Table.class), - anyString(), - anyBoolean(), - any(AsyncCallback.class) + + ArgumentCaptor onUpdateArgumentCaptor = + ArgumentCaptor.forClass(EntityViewScopeEditorModalProps.Callback.class); + ArgumentCaptor onCancelArgumentCaptor = + ArgumentCaptor.forClass(EntityViewScopeEditorModalProps.Callback.class); + verify(mockEntityViewScopeEditorModalWidget) + .configure( + eq(entityId), + onUpdateArgumentCaptor.capture(), + onCancelArgumentCaptor.capture(), + eq(true) ); - verify(mockView).setLoading(false); - verify(mockView).hideModal(); + onUpdateArgumentCaptor.getValue().run(); + verify(mockEntityViewScopeEditorModalWidget).setOpen(false); verify(mockEventBus).fireEvent(any(EntityUpdatedEvent.class)); } + @Test + public void testOnEditScopeAndMaskOnCancel() { + // configure with an entityview, edit the scope, and save. + boolean isEditable = true; + widget.configure(mockBundle, isEditable); + + // The view scope widget does not allow edit of the scope. That occurs in the modal (with the + // editScopeWidget) + verify(mockViewScopeWidget) + .configure(mockReferencesWithoutVersions, false, TableType.file_view); + verify(mockView).setEditMaskAndScopeButtonVisible(true); + verify(mockView).setVisible(true); + + widget.onEditScopeAndMask(); + + ArgumentCaptor onUpdateArgumentCaptor = + ArgumentCaptor.forClass(EntityViewScopeEditorModalProps.Callback.class); + ArgumentCaptor onCancelArgumentCaptor = + ArgumentCaptor.forClass(EntityViewScopeEditorModalProps.Callback.class); + verify(mockEntityViewScopeEditorModalWidget) + .configure( + eq(entityId), + onUpdateArgumentCaptor.capture(), + onCancelArgumentCaptor.capture(), + eq(true) + ); + onCancelArgumentCaptor.getValue().run(); + verify(mockEntityViewScopeEditorModalWidget).setOpen(false); + } + @Test public void testConfigureUnsupportedViewTypeMask() { int unsupportedViewTypeMask = WebConstants.PROJECT | WebConstants.FILE; @@ -213,73 +221,28 @@ public void testConfigureUnsupportedViewTypeMask() { // Simulate clicking the edit button widget.onEditScopeAndMask(); - - // The mask editor should not be visible - verify(mockView).setEditMaskVisible(false); - } - - @Test - public void testConfigureHappyCaseProjectView() { - when(mockEntityView.getType()).thenReturn(ViewType.project); - // configure with an entityview, edit the scope, and save. - boolean isEditable = true; - widget.configure(mockBundle, isEditable); - - // The edit button should be visible - verify(mockView).setEditMaskAndScopeButtonVisible(true); - - // The view scope widget should be configured and not be editable - verify(mockViewScopeWidget) - .configure(mockReferencesWithoutVersions, false, TableType.project_view); - - // Simulate clicking the edit button - widget.onEditScopeAndMask(); - - // The mask editor should not be visible - verify(mockView).setEditMaskVisible(false); - } - - @Test - public void testConfigureFileView() { - when(mockEntityView.getType()).thenReturn(ViewType.file); - boolean isEditable = true; - - widget.configure(mockBundle, isEditable); - widget.onEditScopeAndMask(); - - // The mask editor should be visible - verify(mockView).setEditMaskVisible(true); - - // Show File View options for project view - verify(mockView).setIsFileSelected(true); - verify(mockView).setIsFolderSelected(false); - verify(mockView).setIsTableSelected(false); - verify(mockView).setIsDatasetSelected(false); } @Test - public void testConfigureFileAndTableView() { + public void testConfigureView() { when(mockEntityView.getType()).thenReturn(ViewType.file_and_table); boolean isEditable = true; widget.configure(mockBundle, isEditable); widget.onEditScopeAndMask(); - // The mask editor should be visible - verify(mockView).setEditMaskVisible(true); - - // Show File View options for project view - verify(mockView).setIsFileSelected(true); - verify(mockView).setIsFolderSelected(false); - verify(mockView).setIsTableSelected(true); - verify(mockView).setIsDatasetSelected(false); - - // verify update view type from file+table to file - when(mockView.isFileSelected()).thenReturn(true); - widget.updateViewTypeMask(); - widget.onSave(); - - verify(mockEntityView).setViewTypeMask(ViewTypeMask.File.getMask()); + // verify new editor is configured + ArgumentCaptor onUpdateArgumentCaptor = + ArgumentCaptor.forClass(EntityViewScopeEditorModalProps.Callback.class); + ArgumentCaptor onCancelArgumentCaptor = + ArgumentCaptor.forClass(EntityViewScopeEditorModalProps.Callback.class); + verify(mockEntityViewScopeEditorModalWidget) + .configure( + eq(entityId), + onUpdateArgumentCaptor.capture(), + onCancelArgumentCaptor.capture(), + eq(true) + ); } @Test @@ -302,38 +265,6 @@ public void testConfigureNotEditable() { verify(mockView).setVisible(true); } - @Test - public void testOnSaveFailure() { - Exception ex = new Exception("error on save"); - AsyncMockStubber - .callFailureWith(ex) - .when(mockJsClient) - .updateEntity( - any(Table.class), - anyString(), - anyBoolean(), - any(AsyncCallback.class) - ); - boolean isEditable = true; - - widget.configure(mockBundle, isEditable); - widget.onSave(); - - verify(mockSynapseAlert).clear(); - verify(mockView).setLoading(true); - verify(mockJsClient) - .updateEntity( - any(Table.class), - anyString(), - anyBoolean(), - any(AsyncCallback.class) - ); - verify(mockView).setLoading(false); - verify(mockSynapseAlert).handleException(ex); - verify(mockView, never()).hideModal(); - verify(mockEventBus, never()).fireEvent(any(EntityUpdatedEvent.class)); - } - @Test public void testAsWidget() { widget.asWidget(); From c5af8bcac91b4614e6d33fc28b990d4191fb2513 Mon Sep 17 00:00:00 2001 From: Jin Jun Oh Date: Thu, 29 Feb 2024 13:50:04 -0800 Subject: [PATCH 2/2] SWC-6669: apply changes from review --- .../EntityViewScopeEditorModalProps.java | 1 - .../entity/EntityViewScopeEditorModalWidget.java | 7 ++----- .../entity/SqlDefinedEditorModalWidget.java | 2 -- .../modal/fileview/EntityViewScopeWidget.java | 5 ++--- .../EntityViewScopeEditorModalWidgetTest.java | 5 ++--- .../table/modal/fileview/ScopeWidgetTest.java | 15 ++++++--------- 6 files changed, 12 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityViewScopeEditorModalProps.java b/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityViewScopeEditorModalProps.java index b16c97d8a6..9125be61b2 100644 --- a/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityViewScopeEditorModalProps.java +++ b/src/main/java/org/sagebionetworks/web/client/jsinterop/EntityViewScopeEditorModalProps.java @@ -41,4 +41,3 @@ public static EntityViewScopeEditorModalProps create( return props; } } -// TODO: create EntityViewScopeEditorModalWidget, View, and IMPL diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidget.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidget.java index 3c04b62b67..3577ade14a 100644 --- a/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidget.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidget.java @@ -19,7 +19,6 @@ public class EntityViewScopeEditorModalWidget implements IsWidget { private String entityId; private EntityViewScopeEditorModalProps.Callback onCancel; private EntityViewScopeEditorModalProps.Callback onUpdate; - boolean open; @Inject public EntityViewScopeEditorModalWidget( @@ -34,19 +33,17 @@ public EntityViewScopeEditorModalWidget( public void configure( String entityId, EntityViewScopeEditorModalProps.Callback onUpdate, - EntityViewScopeEditorModalProps.Callback onCancel, - boolean open + EntityViewScopeEditorModalProps.Callback onCancel ) { this.entityId = entityId; this.onUpdate = onUpdate; this.onCancel = onCancel; - this.open = open; EntityViewScopeEditorModalProps props = EntityViewScopeEditorModalProps.create( entityId, onUpdate, onCancel, - open + false ); view.renderComponent(props); } diff --git a/src/main/java/org/sagebionetworks/web/client/widget/entity/SqlDefinedEditorModalWidget.java b/src/main/java/org/sagebionetworks/web/client/widget/entity/SqlDefinedEditorModalWidget.java index 2435748660..c98976527d 100644 --- a/src/main/java/org/sagebionetworks/web/client/widget/entity/SqlDefinedEditorModalWidget.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/entity/SqlDefinedEditorModalWidget.java @@ -11,8 +11,6 @@ public class SqlDefinedEditorModalWidget implements IsWidget { private final GlobalApplicationState globalApplicationState; private final SqlDefinedEditorModalWidgetView view; - private boolean open; - private String entityId; private SqlDefinedTableEditorModalProps.Callback onCancel; private SqlDefinedTableEditorModalProps.Callback onUpdate; diff --git a/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidget.java b/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidget.java index 2b5f68e67d..00cde0df13 100644 --- a/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidget.java +++ b/src/main/java/org/sagebionetworks/web/client/widget/table/modal/fileview/EntityViewScopeWidget.java @@ -42,7 +42,7 @@ public class EntityViewScopeWidget SynapseJavascriptClient jsClient; EntityBundle bundle; EntityContainerListWidget viewScopeWidget; - EntityViewScopeEditorModalWidget editEntityViewScopeModalWidget; // TODO: replace edit scope widget with the react compoenent widget & fix corresponding test + EntityViewScopeEditorModalWidget editEntityViewScopeModalWidget; EntityView currentView; TableType tableType; EventBus eventBus; @@ -132,8 +132,7 @@ public void onEditScopeAndMask() { }, () -> { editEntityViewScopeModalWidget.setOpen(false); - }, - true + } ); editEntityViewScopeModalWidget.setOpen(true); } diff --git a/src/test/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetTest.java b/src/test/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetTest.java index 8d9bedb1e1..4b52b0af0b 100644 --- a/src/test/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetTest.java +++ b/src/test/java/org/sagebionetworks/web/client/widget/entity/EntityViewScopeEditorModalWidgetTest.java @@ -53,15 +53,14 @@ public void validate() { } @Test - public void testConstruction() { - widget.configure(ENTITY_ID, mockOnUpdate, mockOnCancel, open); + public void testConfigure() { + widget.configure(ENTITY_ID, mockOnUpdate, mockOnCancel); verify(mockView).renderComponent(propsCaptor.capture()); EntityViewScopeEditorModalProps capturedProps = propsCaptor.getValue(); assertEquals(ENTITY_ID, capturedProps.entityId); assertEquals(mockOnUpdate, capturedProps.onUpdate); assertEquals(mockOnCancel, capturedProps.onCancel); - assertEquals(open, capturedProps.open); } @Test diff --git a/src/test/java/org/sagebionetworks/web/unitclient/widget/table/modal/fileview/ScopeWidgetTest.java b/src/test/java/org/sagebionetworks/web/unitclient/widget/table/modal/fileview/ScopeWidgetTest.java index 13c53c9621..757ffea9e9 100644 --- a/src/test/java/org/sagebionetworks/web/unitclient/widget/table/modal/fileview/ScopeWidgetTest.java +++ b/src/test/java/org/sagebionetworks/web/unitclient/widget/table/modal/fileview/ScopeWidgetTest.java @@ -1,8 +1,7 @@ package org.sagebionetworks.web.unitclient.widget.table.modal.fileview; import static org.mockito.Matchers.*; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import com.google.gwt.event.shared.EventBus; import com.google.gwt.user.client.rpc.AsyncCallback; @@ -160,8 +159,7 @@ public void testOnEditScopeAndMaskOnUpdate() { .configure( eq(entityId), onUpdateArgumentCaptor.capture(), - onCancelArgumentCaptor.capture(), - eq(true) + onCancelArgumentCaptor.capture() ); onUpdateArgumentCaptor.getValue().run(); verify(mockEntityViewScopeEditorModalWidget).setOpen(false); @@ -191,11 +189,11 @@ public void testOnEditScopeAndMaskOnCancel() { .configure( eq(entityId), onUpdateArgumentCaptor.capture(), - onCancelArgumentCaptor.capture(), - eq(true) + onCancelArgumentCaptor.capture() ); onCancelArgumentCaptor.getValue().run(); verify(mockEntityViewScopeEditorModalWidget).setOpen(false); + verify(mockEventBus, never()).fireEvent(any(EntityUpdatedEvent.class)); } @Test @@ -239,9 +237,8 @@ public void testConfigureView() { verify(mockEntityViewScopeEditorModalWidget) .configure( eq(entityId), - onUpdateArgumentCaptor.capture(), - onCancelArgumentCaptor.capture(), - eq(true) + any(EntityViewScopeEditorModalProps.Callback.class), + any(EntityViewScopeEditorModalProps.Callback.class) ); }