From b55aff673dcb8c8a4da7d7301a5fd61596795ca3 Mon Sep 17 00:00:00 2001 From: Costantino Perciante Date: Tue, 23 Jan 2018 17:25:16 +0000 Subject: [PATCH] some of the fixes reported in #10928 git-svn-id: http://svn.research-infrastructures.eu/public/d4science/gcube/trunk/portlets/widgets/grsf-manage-widget@162494 82a268e6-3cf1-43bd-a215-b396298e98cf --- .classpath | 1 + .../client/GRSFManageWidgetService.java | 8 +- .../client/GRSFManageWidgetServiceAsync.java | 4 +- .../client/view/ManageProductWidget.java | 32 ++- .../client/view/ManageProductWidget.ui.xml | 17 +- .../view/subwidgets/ConnectToWidget.java | 108 +++++-- .../subwidgets/SimilarGRSFRecordWidget.java | 223 +++++---------- .../subwidgets/SimilarGRSFRecordWidget.ui.xml | 8 +- .../client/view/subwidgets/SuggestMerges.java | 267 ++++++++++++++++++ .../view/subwidgets/SuggestMerges.ui.xml | 9 + .../manage/GRSFNotificationService.java | 17 +- .../server/manage/Utils.java | 10 +- .../shared/ConnectedBean.java | 36 ++- .../shared/SimilarGRSFRecord.java | 47 +-- 14 files changed, 560 insertions(+), 227 deletions(-) create mode 100644 src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SuggestMerges.java create mode 100644 src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SuggestMerges.ui.xml diff --git a/.classpath b/.classpath index edad874..eeb63b8 100644 --- a/.classpath +++ b/.classpath @@ -20,6 +20,7 @@ + diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetService.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetService.java index 219939b..c0fcf38 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetService.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetService.java @@ -47,18 +47,18 @@ public interface GRSFManageWidgetService extends RemoteService { /** * Identifier of the record (UUID) * @param id - * @return + * @return the url of the record * @throws Exception */ - boolean checkIdentifierExists(String id) throws Exception; + String checkIdentifierExists(String id) throws Exception; /** * Identifier of the record (UUID) * @param id * @param domain (stock or fishery) - * @return + * @return the url of the record * @throws Exception */ - boolean checkIdentifierExistsInDomain(String id, String domain) throws Exception; + String checkIdentifierExistsInDomain(String id, String domain) throws Exception; } diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetServiceAsync.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetServiceAsync.java index bfaec9a..6501992 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetServiceAsync.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/GRSFManageWidgetServiceAsync.java @@ -28,9 +28,9 @@ public interface GRSFManageWidgetServiceAsync { String domain, AsyncCallback callback); void checkIdentifierExists(String id, - AsyncCallback callback); + AsyncCallback callback); void checkIdentifierExistsInDomain(String id, - String domain, AsyncCallback callback); + String domain, AsyncCallback callback); } diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java index bf7155f..a375ebf 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.java @@ -15,6 +15,7 @@ import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.Connect import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.FormEntryModel; import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.SimilarGRSFRecordWidget; import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.SourceWidget; +import org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets.SuggestMerges; import org.gcube.datacatalogue.grsf_manage_widget.shared.ManageProductBean; import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord; import org.gcube.datacatalogue.grsf_manage_widget.shared.SourceRecord; @@ -35,6 +36,7 @@ import com.github.gwtbootstrap.client.ui.constants.AlertType; import com.github.gwtbootstrap.client.ui.constants.ControlGroupType; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.SelectElement; +import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.shared.HandlerManager; import com.google.gwt.uibinder.client.UiBinder; @@ -64,7 +66,7 @@ public class ManageProductWidget extends Composite{ @UiField VerticalPanel container; - + @UiField Modal manageProductModal; @@ -91,6 +93,9 @@ public class ManageProductWidget extends Composite{ @UiField VerticalPanel panelForSimilarGRSFRecords; + + @UiField + VerticalPanel panelForFurtherMerges; @UiField VerticalPanel panelForConnectOtherRecords; @@ -148,6 +153,7 @@ public class ManageProductWidget extends Composite{ // similar records and to connect widgets references private SimilarGRSFRecordWidget similarRecordPanel; + private SuggestMerges suggestedMergesPanel; private ConnectToWidget connectWidget; /** @@ -171,8 +177,8 @@ public class ManageProductWidget extends Composite{ // show modal manageProductModal.addStyleName("management-metadata-modal-style"); + manageProductModal.getElement().getStyle().setWidth(60, Unit.PCT); manageProductModal.show(); - // async request to fetch the product retrieveProductBean(productIdentifier); @@ -227,7 +233,8 @@ public class ManageProductWidget extends Composite{ productGrsfType.setText(bean.getGrsfType()); currentStatus.setText(bean.getCurrentStatus().toString()); traceabilityFlag.setValue(bean.isTraceabilityFlag()); - traceabilityFlag.setTitle("Current value for the record is " + bean.isTraceabilityFlag()); + traceabilityFlag.setText("Traceability"); + traceabilityFlag.setTitle("Current value for this flag in the Knowledge Base is " + bean.isTraceabilityFlag()); // manage sources List availableSources = bean.getSources(); @@ -237,9 +244,13 @@ public class ManageProductWidget extends Composite{ List availableGRSFSimilarRecords = bean.getSimilarGrsfRecords(); similarRecordPanel = new SimilarGRSFRecordWidget(availableGRSFSimilarRecords/*, service*/); panelForSimilarGRSFRecords.add(similarRecordPanel); + + // further suggested merges + suggestedMergesPanel = new SuggestMerges(service); + panelForFurtherMerges.add(suggestedMergesPanel); // prepare "connect" panel - connectWidget = new ConnectToWidget(bean /*,service*/); + connectWidget = new ConnectToWidget(bean, service); panelForConnectOtherRecords.add(connectWidget); // check if we need to show more @@ -335,11 +346,11 @@ public class ManageProductWidget extends Composite{ annotationAreaGroup.setType(ControlGroupType.NONE); - if(annotationArea.getText() == null || annotationArea.getText().isEmpty()){ - annotationArea.setPlaceholder("An annotation message to send along the update (mandatory)"); - annotationAreaGroup.setType(ControlGroupType.ERROR); - return; - } + // if(annotationArea.getText() == null || annotationArea.getText().isEmpty()){ + // annotationArea.setPlaceholder("An annotation message to send along the update (mandatory)"); + // annotationAreaGroup.setType(ControlGroupType.ERROR); + // return; + // } manageProductModal.setCloseVisible(false); cancelButton.setEnabled(false); @@ -352,11 +363,12 @@ public class ManageProductWidget extends Composite{ // update similar records and to connect bean.setConnectTo(connectWidget.getConnectList()); bean.setSimilarGrsfRecords(similarRecordPanel.getSimilarRecords()); + bean.getSimilarGrsfRecords().addAll(suggestedMergesPanel.getSimilarRecords()); // set new values bean.setAnnotation(new HTML(annotationArea.getText().trim()).getText()); bean.setNewStatus(Status.fromString(listBoxStatus.getSelectedItemText())); - + // traceability flag bean.setTraceabilityFlag(traceabilityFlag.getValue()); diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.ui.xml b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.ui.xml index c8627a6..57b5f4e 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.ui.xml +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/ManageProductWidget.ui.xml @@ -93,8 +93,8 @@ - - Similar GRSF Records: + + Merge Records (Notification will be sent): + + + + Suggest Merges (Notification will be sent): + + + + + + - Suggest connections with other records: + Suggest connections with other records (Traceability Purpose): { } @@ -51,8 +57,12 @@ public class ConnectToWidget extends Composite{ private List connectedRecords = null; - public ConnectToWidget(final ManageProductBean bean/*, GRSFManageWidgetServiceAsync service*/) { + private GRSFManageWidgetServiceAsync service; + + public ConnectToWidget(final ManageProductBean bean, GRSFManageWidgetServiceAsync service) { initWidget(uiBinder.createAndBindUi(this)); + + this.service = service; // get already connected beans, if any connectedRecords = bean.getConnectTo(); @@ -79,7 +89,7 @@ public class ConnectToWidget extends Composite{ public void onClick(ClickEvent arg0) { ConnectedBean cb = new ConnectedBean(); - cb.setExtra(true); + // cb.setExtra(true); cb.setSourceDomain(bean.getGrsfDomain()); Tuple t = buildWidgetConnect(cb); connectList.add(t); @@ -123,7 +133,7 @@ public class ConnectToWidget extends Composite{ rightPanel.setWidth("20%"); final CheckBox removeExtra = new CheckBox("Remove"); - removeExtra.setTitle("Remove this record among the similar ones"); + removeExtra.setTitle("Remove this record among the connected ones"); removeExtra.addClickHandler(new ClickHandler() { @Override @@ -149,7 +159,7 @@ public class ConnectToWidget extends Composite{ private Tuple buildWidgetConnect(final ConnectedBean cb){ VerticalPanel main = new VerticalPanel(); - main.setWidth("95%"); + main.setWidth("100%"); HorizontalPanel hp = new HorizontalPanel(); hp.setWidth("100%"); @@ -158,31 +168,33 @@ public class ConnectToWidget extends Composite{ vpLeft.setWidth("80%"); Paragraph semanticIdentifier = new Paragraph("Identifier (UUID):"); final TextBox box = new TextBox(); - box.setId("identifier-text"); + final Icon icon = new Icon(IconType.OK_SIGN); + final Anchor view = new Anchor(); + view.setText("View"); + view.setTitle("Click to inspect the record"); + view.setTarget("_blank"); + view.getElement().getStyle().setFontWeight(FontWeight.BOLD); + view.setVisible(false); + icon.setVisible(false); box.addKeyPressHandler(new KeyPressHandler() { @Override public void onKeyPress(KeyPressEvent event) { - - String currentText = box.getText().trim(); - GWT.log("Text changed to " + currentText); - cb.setDestKnowledgeBaseId(currentText); - + GWT.log("onKeyPress " + event.getNativeEvent().getKeyCode()); + if(!(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_BACKSPACE || event.getNativeEvent().getKeyCode() == KeyCodes.KEY_DELETE)) + validateUUID(box, cb, icon, view); } }); box.addChangeHandler(new ChangeHandler() { @Override public void onChange(ChangeEvent event) { - - String currentText = box.getText().trim(); - GWT.log("Text changed to " + currentText); - cb.setDestKnowledgeBaseId(currentText); - + GWT.log("onChange"); + validateUUID(box, cb, icon, view); } }); box.setWidth("512px"); - box.setPlaceholder("Insert the Identifier (UUID) of the record to connect"); + box.setPlaceholder("Insert the Identifier (UUID) of the record to connect and press ENTER"); vpLeft.add(semanticIdentifier); vpLeft.add(box); @@ -220,6 +232,65 @@ public class ConnectToWidget extends Composite{ main.add(separator); return new Tuple(cb, main, box); } + + protected void validateUUID(final TextBox box, final ConnectedBean c, final Icon icon, final Anchor view) { + + final String currentText = box.getText().trim(); + + if(currentText == null || currentText.isEmpty()){ + icon.setVisible(false); + view.setVisible(false); + return; + } + + if(!currentText.matches(REGEX_UUID)){ + icon.setType(IconType.BAN_CIRCLE); + icon.setTitle("Not a valid UUID"); + icon.setVisible(true); + view.setVisible(false); + return; + } + + // else check at server side if it exists + GWT.log("Text changed to " + currentText); + box.setEnabled(false); + icon.setIcon(IconType.ROTATE_RIGHT); + icon.setSpin(true); + + service.checkIdentifierExists(currentText, new AsyncCallback() { + + @Override + public void onSuccess(String result) { + + if(result != null){ + c.setDestKnowledgeBaseId(currentText); + icon.setType(IconType.OK_CIRCLE); + icon.setSpin(false); + icon.setTitle(""); + icon.setVisible(true); + view.setHref(result); + view.setVisible(true); + } + else{ + icon.setType(IconType.BAN_CIRCLE); + icon.setTitle("Not a valid UUID"); + icon.setSpin(false); + icon.setVisible(true); + view.setVisible(false); + } + + box.setEnabled(true); + } + + @Override + public void onFailure(Throwable caught) { + box.setEnabled(true); + icon.setSpin(false); + view.setVisible(false); + } + }); + + } /** * Get the list of records to connect with this one @@ -234,8 +305,11 @@ public class ConnectToWidget extends Composite{ String suggestedIdentifier = ((ConnectedBean)p.getO()).getDestKnowledgeBaseId(); if(suggestedIdentifier == null || suggestedIdentifier.isEmpty()) continue; - else + else{ + ConnectedBean connectedRecord = (ConnectedBean) p.getO(); + connectedRecord.setToBeKept(true); connectedRecords.add((ConnectedBean) p.getO()); + } } return connectedRecords; diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SimilarGRSFRecordWidget.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SimilarGRSFRecordWidget.java index e0240fb..3243c31 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SimilarGRSFRecordWidget.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SimilarGRSFRecordWidget.java @@ -1,7 +1,6 @@ package org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord; @@ -9,18 +8,13 @@ import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord; import com.github.gwtbootstrap.client.ui.Button; import com.github.gwtbootstrap.client.ui.CheckBox; import com.github.gwtbootstrap.client.ui.Paragraph; -import com.github.gwtbootstrap.client.ui.TextBox; -import com.github.gwtbootstrap.client.ui.constants.IconType; +import com.github.gwtbootstrap.client.ui.constants.ButtonType; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Style.Float; import com.google.gwt.dom.client.Style.FontWeight; import com.google.gwt.dom.client.Style.Unit; -import com.google.gwt.event.dom.client.ChangeEvent; -import com.google.gwt.event.dom.client.ChangeHandler; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; -import com.google.gwt.event.dom.client.KeyPressEvent; -import com.google.gwt.event.dom.client.KeyPressHandler; import com.google.gwt.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.user.client.ui.Anchor; @@ -32,6 +26,10 @@ import com.google.gwt.user.client.ui.Widget; public class SimilarGRSFRecordWidget extends Composite { + private static final int THRESHOLD_SET_HIDDEN = 5; + + private static final String SEE_MORE = "See More"; + private static final String SEE_LESS = "See Less"; private static SimilarGRSFRecordWidgetUiBinder uiBinder = GWT .create(SimilarGRSFRecordWidgetUiBinder.class); @@ -42,14 +40,17 @@ public class SimilarGRSFRecordWidget extends Composite { @UiField VerticalPanel similarGrsfRecordsPanel; + // @UiField + // VerticalPanel similarGrsfRecordsSuggestedPanel; + // + // @UiField + // Button addSimilarRecord; @UiField - VerticalPanel similarGrsfRecordsSuggestedPanel; + Button viewMore; - @UiField - Button addSimilarRecord; - - private List extraSimilarRecordsList = new ArrayList(0); + // private List extraSimilarRecordsList = new ArrayList(0); private List availableGRSFSimilarRecords; + private List toHide = new ArrayList(); //private GRSFManageWidgetServiceAsync service; /** @@ -66,41 +67,63 @@ public class SimilarGRSFRecordWidget extends Composite { if(availableGRSFSimilarRecords != null){ similarGrsfRecordsPanel.add(new HTML("
")); - + + boolean visibleMore = true; + viewMore.setText(SEE_MORE); + if(availableGRSFSimilarRecords.size() > THRESHOLD_SET_HIDDEN){ + visibleMore = false; + viewMore.getElement().getStyle().setFloat(Float.RIGHT); + viewMore.setType(ButtonType.LINK); + viewMore.setVisible(true); + viewMore.getElement().getStyle().setFontWeight(FontWeight.BOLD); + viewMore.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent event) { + event.preventDefault(); + + boolean toShow = false; + if(viewMore.getText().trim().equals(SEE_MORE)){ + viewMore.setText(SEE_LESS); + toShow = true; + } + else{ + viewMore.setText(SEE_MORE); + toShow = false; + } + + for(Widget w: toHide) + w.setVisible(toShow); + + } + }); + } + // add the existing ones, if any + int index = 0; for (final SimilarGRSFRecord similarGRSFRecord : availableGRSFSimilarRecords) { Widget widget = buildWidgetForSimilarRecord(similarGRSFRecord); similarGrsfRecordsPanel.add(widget); - similarGrsfRecordsPanel.add(new HTML("
")); + HTML separator = new HTML("
"); + similarGrsfRecordsPanel.add(separator); + if(index >= THRESHOLD_SET_HIDDEN){ + widget.setVisible(visibleMore); + separator.setVisible(visibleMore); + toHide.add(widget); + toHide.add(separator); + } + index++; } } - // manage the "suggest button" - addSimilarRecord.setIcon(IconType.PLUS_SIGN); - addSimilarRecord.getElement().getStyle().setFloat(Float.RIGHT); - addSimilarRecord.setTitle("Suggest a Similar Record by using its Identifier (UUID)"); - addSimilarRecord.getElement().getStyle().setFloat(Float.RIGHT); - - // add handler - addSimilarRecord.addClickHandler(new ClickHandler() { - - @Override - public void onClick(ClickEvent arg0) { - - SimilarGRSFRecord s = new SimilarGRSFRecord(); - s.setExtra(true); - Widget w = buildWidgetForExtraSimilarRecord(s); - extraSimilarRecordsList.add(new Tuple(s, w, null)); - similarGrsfRecordsSuggestedPanel.add(w); - - } - }); } /** * Builds widget for already present similar GRSF records * @param similarGRSFRecord + * @param hideMore + * @param index * @return a Widget (actually a VerticalPanel) */ public static Widget buildWidgetForSimilarRecord(final SimilarGRSFRecord similarGRSFRecord){ @@ -128,7 +151,7 @@ public class SimilarGRSFRecordWidget extends Composite { Anchor view = new Anchor(); view.setHref(similarGRSFRecord.getUrl()); view.setText("View"); - view.setTitle("Click to view the similar record"); + view.setTitle("Click to inspect the similar record"); view.setTarget("_blank"); view.getElement().getStyle().setFontWeight(FontWeight.BOLD); leftPanel.add(view); @@ -152,20 +175,20 @@ public class SimilarGRSFRecordWidget extends Composite { } }); - final CheckBox removeExtra = new CheckBox("Remove"); - removeExtra.getElement().getStyle().setPaddingTop(3, Unit.PC); - removeExtra.setTitle("Remove this record among the similar ones"); - removeExtra.addClickHandler(new ClickHandler() { - - @Override - public void onClick(ClickEvent arg0) { - similarGRSFRecord.setToBeKept(!removeExtra.getValue()); - } - }); + // final CheckBox removeExtra = new CheckBox("Remove"); + // removeExtra.getElement().getStyle().setPaddingTop(3, Unit.PC); + // removeExtra.setTitle("Remove this record among the similar ones"); + // removeExtra.addClickHandler(new ClickHandler() { + // + // @Override + // public void onClick(ClickEvent arg0) { + // similarGRSFRecord.setToBeKept(!removeExtra.getValue()); + // } + // }); rightPanel.getElement().getStyle().setFloat(Float.RIGHT); rightPanel.add(mergeSuggested); - rightPanel.add(removeExtra); + // rightPanel.add(removeExtra); hp.add(leftPanel); hp.add(rightPanel); hp.getElement().getStyle().setPadding(10, Unit.PX); @@ -173,102 +196,6 @@ public class SimilarGRSFRecordWidget extends Composite { return hp; } - /** - * Builds up a widget for suggested similar grsf records. Changes are performed in place with respect to w and s. - * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) - * @param w the widget - * @param s the similar record. - */ - private Widget buildWidgetForExtraSimilarRecord(final SimilarGRSFRecord s){ - - VerticalPanel main = new VerticalPanel(); - main.setWidth("95%"); - HorizontalPanel hp = new HorizontalPanel(); - hp.setWidth("100%"); - - VerticalPanel vpLeft = new VerticalPanel(); - vpLeft.getElement().getStyle().setMarginLeft(15, Unit.PX); - vpLeft.setWidth("80%"); - Paragraph identifier = new Paragraph("Identifier (UUID):"); - final TextBox box = new TextBox(); - box.addKeyPressHandler(new KeyPressHandler() { - - @Override - public void onKeyPress(KeyPressEvent event) { - - String currentText = box.getText().trim(); - GWT.log("Text changed to " + currentText); - s.setKnowledgeBaseId(currentText); - - } - }); - box.addChangeHandler(new ChangeHandler() { - - @Override - public void onChange(ChangeEvent event) { - - String currentText = box.getText().trim(); - GWT.log("Text changed to " + currentText); - s.setKnowledgeBaseId(currentText); - - } - }); - box.setWidth("511px"); - box.setPlaceholder("Insert the Identifier (UUID) of the suggested record"); - - vpLeft.add(identifier); - vpLeft.add(box); - - // add merge checkbox - final CheckBox mergeSuggested = new CheckBox("Merge"); - mergeSuggested.setTitle("Suggest to merge the current record with this similar record"); - mergeSuggested.getElement().getStyle().setPaddingTop(3, Unit.PC); - mergeSuggested.setValue(false); - - VerticalPanel vpRight = new VerticalPanel(); - vpRight.setWidth("20%"); - mergeSuggested.addClickHandler(new ClickHandler() { - - @Override - public void onClick(ClickEvent arg0) { - s.setSuggestedMerge(mergeSuggested.getValue()); - } - }); - - vpRight.add(mergeSuggested); - - Button removeExtra = new Button(); - removeExtra.setIcon(IconType.MINUS); - removeExtra.setTitle("Remove this suggested record"); - removeExtra.addClickHandler(new ClickHandler() { - - @Override - public void onClick(ClickEvent arg0) { - - // remove this object from the pairs list - Iterator iterator = extraSimilarRecordsList.iterator(); - while (iterator.hasNext()) { - Tuple pair = (Tuple) iterator - .next(); - if(pair.getO().equals(s)){ - pair.getW().removeFromParent(); - iterator.remove(); - } - } - } - }); - vpRight.getElement().getStyle().setFloat(Float.RIGHT); - vpRight.add(removeExtra); - vpRight.add(mergeSuggested); - hp.add(vpLeft); - hp.add(vpRight); - HTML separator = new HTML("
"); - similarGrsfRecordsSuggestedPanel.add(separator); - main.add(hp); - main.add(separator); - return main; - } - /** * Get the whole of similar records * @return @@ -278,12 +205,12 @@ public class SimilarGRSFRecordWidget extends Composite { if(availableGRSFSimilarRecords == null) availableGRSFSimilarRecords = new ArrayList(); - for (Tuple p : extraSimilarRecordsList) { - SimilarGRSFRecord similarRecord = ((SimilarGRSFRecord)p.getO()); - if(similarRecord.isExtra() && similarRecord.getKnowledgeBaseId() == null || similarRecord.getKnowledgeBaseId().isEmpty()) - continue; - availableGRSFSimilarRecords.add((SimilarGRSFRecord) p.getO()); - } + // for (Tuple p : extraSimilarRecordsList) { + // SimilarGRSFRecord similarRecord = ((SimilarGRSFRecord)p.getO()); + // if(similarRecord.getKnowledgeBaseId() == null || similarRecord.getKnowledgeBaseId().isEmpty()) + // continue; + // availableGRSFSimilarRecords.add((SimilarGRSFRecord) p.getO()); + // } return availableGRSFSimilarRecords; diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SimilarGRSFRecordWidget.ui.xml b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SimilarGRSFRecordWidget.ui.xml index 20ca4b3..ca339f1 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SimilarGRSFRecordWidget.ui.xml +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SimilarGRSFRecordWidget.ui.xml @@ -3,8 +3,10 @@ xmlns:g="urn:import:com.google.gwt.user.client.ui" xmlns:b="urn:import:com.github.gwtbootstrap.client.ui"> - - - + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SuggestMerges.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SuggestMerges.java new file mode 100644 index 0000000..68ac813 --- /dev/null +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SuggestMerges.java @@ -0,0 +1,267 @@ +package org.gcube.datacatalogue.grsf_manage_widget.client.view.subwidgets; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.gcube.datacatalogue.grsf_manage_widget.client.GRSFManageWidgetServiceAsync; +import org.gcube.datacatalogue.grsf_manage_widget.shared.SimilarGRSFRecord; + +import com.github.gwtbootstrap.client.ui.Button; +import com.github.gwtbootstrap.client.ui.Icon; +import com.github.gwtbootstrap.client.ui.Paragraph; +import com.github.gwtbootstrap.client.ui.TextBox; +import com.github.gwtbootstrap.client.ui.constants.IconType; +import com.google.gwt.core.client.GWT; +import com.google.gwt.dom.client.Style.Float; +import com.google.gwt.dom.client.Style.FontWeight; +import com.google.gwt.dom.client.Style.Unit; +import com.google.gwt.event.dom.client.ChangeEvent; +import com.google.gwt.event.dom.client.ChangeHandler; +import com.google.gwt.event.dom.client.ClickEvent; +import com.google.gwt.event.dom.client.ClickHandler; +import com.google.gwt.event.dom.client.KeyCodes; +import com.google.gwt.event.dom.client.KeyPressEvent; +import com.google.gwt.event.dom.client.KeyPressHandler; +import com.google.gwt.uibinder.client.UiBinder; +import com.google.gwt.uibinder.client.UiField; +import com.google.gwt.user.client.rpc.AsyncCallback; +import com.google.gwt.user.client.ui.Anchor; +import com.google.gwt.user.client.ui.Composite; +import com.google.gwt.user.client.ui.HTML; +import com.google.gwt.user.client.ui.HorizontalPanel; +import com.google.gwt.user.client.ui.VerticalPanel; +import com.google.gwt.user.client.ui.Widget; + +public class SuggestMerges extends Composite { + + private static SuggestMergesUiBinder uiBinder = GWT + .create(SuggestMergesUiBinder.class); + + @UiField + VerticalPanel similarGrsfRecordsSuggestedPanel; + + @UiField + Button addSimilarRecord; + + private List extraSimilarRecordsList = new ArrayList(0); + + private static final String REGEX_UUID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; + + interface SuggestMergesUiBinder extends UiBinder { + } + + private GRSFManageWidgetServiceAsync service; + + public SuggestMerges(GRSFManageWidgetServiceAsync service) { + initWidget(uiBinder.createAndBindUi(this)); + this.service = service; + // manage the "suggest button" + addSimilarRecord.setIcon(IconType.PLUS_SIGN); + addSimilarRecord.getElement().getStyle().setFloat(Float.RIGHT); + addSimilarRecord.setTitle("Suggest a Similar Record by using its Identifier (UUID)"); + addSimilarRecord.getElement().getStyle().setFloat(Float.RIGHT); + + // add handler + addSimilarRecord.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent arg0) { + + SimilarGRSFRecord s = new SimilarGRSFRecord(); + // s.setExtra(true); + Widget w = buildWidgetForExtraSimilarRecord(s); + extraSimilarRecordsList.add(new Tuple(s, w, null)); + similarGrsfRecordsSuggestedPanel.add(w); + + } + }); + } + + /** + * Builds up a widget for suggested similar grsf records. Changes are performed in place with respect to w and s. + * @author Costantino Perciante at ISTI-CNR (costantino.perciante@isti.cnr.it) + * @param w the widget + * @param s the similar record. + */ + private Widget buildWidgetForExtraSimilarRecord(final SimilarGRSFRecord s){ + + VerticalPanel main = new VerticalPanel(); + main.getElement().getStyle().setMarginTop(10, Unit.PX); + main.setWidth("100%"); + HorizontalPanel hp = new HorizontalPanel(); + hp.setWidth("100%"); + + VerticalPanel vpLeft = new VerticalPanel(); + vpLeft.getElement().getStyle().setMarginLeft(15, Unit.PX); + vpLeft.setWidth("80%"); + + HorizontalPanel textBoxIconContainer = new HorizontalPanel(); + textBoxIconContainer.setWidth("100%"); + Paragraph identifier = new Paragraph("Identifier (UUID):"); + final TextBox box = new TextBox(); + final Icon icon = new Icon(IconType.OK_SIGN); + final Anchor view = new Anchor(); + view.setText("View"); + view.setTitle("Click to inspect the record"); + view.setTarget("_blank"); + view.getElement().getStyle().setFontWeight(FontWeight.BOLD); + view.setVisible(false); + icon.setVisible(false); + box.addKeyPressHandler(new KeyPressHandler() { + + @Override + public void onKeyPress(KeyPressEvent event) { + GWT.log("onKeyPress " + event.getNativeEvent().getKeyCode()); + if(!(event.getNativeEvent().getKeyCode() == KeyCodes.KEY_BACKSPACE || event.getNativeEvent().getKeyCode() == KeyCodes.KEY_DELETE)) + validateUUID(box, s, icon, view); + } + }); + box.addChangeHandler(new ChangeHandler() { + + @Override + public void onChange(ChangeEvent event) { + GWT.log("onChange"); + validateUUID(box, s, icon, view); + } + }); + box.setWidth("511px"); + box.setPlaceholder("Insert the Identifier (UUID) of the suggested record"); + vpLeft.add(identifier); + textBoxIconContainer.add(box); + textBoxIconContainer.add(icon); + vpLeft.add(textBoxIconContainer); + vpLeft.add(view); + + // add merge checkbox + // final CheckBox mergeSuggested = new CheckBox("Merge"); + // mergeSuggested.setTitle("Suggest to merge the current record with this similar record"); + // mergeSuggested.getElement().getStyle().setPaddingTop(3, Unit.PC); + // mergeSuggested.setValue(false); + + VerticalPanel vpRight = new VerticalPanel(); + vpRight.setWidth("20%"); + // mergeSuggested.addClickHandler(new ClickHandler() { + // + // @Override + // public void onClick(ClickEvent arg0) { + // s.setSuggestedMerge(mergeSuggested.getValue()); + // } + // }); + // + // vpRight.add(mergeSuggested); + + Button removeExtra = new Button(); + removeExtra.setIcon(IconType.MINUS); + removeExtra.setTitle("Remove this suggested merge"); + removeExtra.getElement().getStyle().setFloat(Float.RIGHT); + removeExtra.addClickHandler(new ClickHandler() { + + @Override + public void onClick(ClickEvent arg0) { + + // remove this object from the pairs list + Iterator iterator = extraSimilarRecordsList.iterator(); + while (iterator.hasNext()) { + Tuple pair = (Tuple) iterator + .next(); + if(pair.getO().equals(s)){ + pair.getW().removeFromParent(); + iterator.remove(); + } + } + } + }); + vpRight.getElement().getStyle().setFloat(Float.RIGHT); + vpRight.add(removeExtra); + // vpRight.add(mergeSuggested); + hp.add(vpLeft); + hp.add(vpRight); + HTML separator = new HTML("
"); + similarGrsfRecordsSuggestedPanel.add(separator); + main.add(hp); + main.add(separator); + return main; + } + + protected void validateUUID(final TextBox box, final SimilarGRSFRecord s, final Icon icon, final Anchor view) { + + final String currentText = box.getText().trim(); + + if(currentText == null || currentText.isEmpty()){ + s.setKnowledgeBaseId(null); + icon.setVisible(false); + view.setVisible(false); + return; + } + + if(!currentText.matches(REGEX_UUID)){ + s.setKnowledgeBaseId(null); + icon.setType(IconType.BAN_CIRCLE); + icon.setTitle("Not a valid UUID"); + icon.setVisible(true); + view.setVisible(false); + return; + } + + // else check at server side if it exists + GWT.log("Text changed to " + currentText); + box.setEnabled(false); + icon.setIcon(IconType.ROTATE_RIGHT); + icon.setSpin(true); + + service.checkIdentifierExists(currentText, new AsyncCallback() { + + @Override + public void onSuccess(String result) { + + if(result != null){ + s.setKnowledgeBaseId(currentText); + icon.setType(IconType.OK_CIRCLE); + icon.setSpin(false); + icon.setTitle(""); + icon.setVisible(true); + view.setHref(result); + view.setVisible(true); + } + else{ + s.setKnowledgeBaseId(null); + icon.setType(IconType.BAN_CIRCLE); + icon.setTitle("Not a valid UUID"); + icon.setSpin(false); + icon.setVisible(true); + view.setVisible(false); + } + + box.setEnabled(true); + } + + @Override + public void onFailure(Throwable caught) { + s.setKnowledgeBaseId(null); + box.setEnabled(true); + icon.setSpin(false); + view.setVisible(false); + } + }); + + } + + /** + * Get the whole of similar records + * @return + */ + public List getSimilarRecords(){ + ArrayList toReturn = new ArrayList(); + + for (Tuple p : extraSimilarRecordsList) { + SimilarGRSFRecord similarRecord = ((SimilarGRSFRecord)p.getO()); + if(similarRecord.getKnowledgeBaseId() == null || similarRecord.getKnowledgeBaseId().isEmpty()) + continue; + toReturn.add((SimilarGRSFRecord) p.getO()); + } + + return toReturn; + } + +} diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SuggestMerges.ui.xml b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SuggestMerges.ui.xml new file mode 100644 index 0000000..5e7678d --- /dev/null +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/client/view/subwidgets/SuggestMerges.ui.xml @@ -0,0 +1,9 @@ + + + + + + + \ No newline at end of file diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFNotificationService.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFNotificationService.java index 48377f4..4fe0004 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFNotificationService.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/GRSFNotificationService.java @@ -287,33 +287,38 @@ public class GRSFNotificationService extends RemoteServiceServlet implements GRS @Override - public boolean checkIdentifierExists(String id) + public String checkIdentifierExists(String id) throws Exception { String scopePerCurrentUrl = Utils.getScopeFromClientUrl(getThreadLocalRequest()); DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl); String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername(); - return catalogue.getDataset(id, catalogue.getApiKeyFromUsername(username)) != null; + CkanDataset dataset = catalogue.getDataset(id, catalogue.getApiKeyFromUsername(username)); + if(dataset == null) + throw new Exception("This record doesn't exist"); + + return dataset.getExtrasAsHashMap().get(Constants.ITEM_URL_FIELD); } @Override - public boolean checkIdentifierExistsInDomain(String id, + public String checkIdentifierExistsInDomain(String id, String domain) throws Exception { String scopePerCurrentUrl = Utils.getScopeFromClientUrl(getThreadLocalRequest()); DataCatalogue catalogue = getCatalogue(scopePerCurrentUrl); String username = Utils.getCurrentUser(getThreadLocalRequest()).getUsername(); CkanDataset dataset = catalogue.getDataset(id, catalogue.getApiKeyFromUsername(username)); if(dataset == null) - return false; + throw new Exception("This record doesn't exist"); List extrasAsPairs = dataset.getExtras(); for (CkanPair ckanPair : extrasAsPairs) { if(ckanPair.getKey().contains(Constants.DOMAIN_CUSTOM_KEY)){ - return ckanPair.getValue().equalsIgnoreCase(domain); + if(ckanPair.getValue().equalsIgnoreCase(domain)) + return dataset.getExtrasAsHashMap().get(Constants.ITEM_URL_FIELD); } } - return false; + throw new Exception("This record doesn't exist in the specified domain"); } @Override diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java index 7c4a63a..bf6f5c8 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/server/manage/Utils.java @@ -298,8 +298,8 @@ public class Utils { cc.put(Constants.SOURCE_KNOWLEDGE_BASE_ID, c.getSourceKnowledgeBaseId()); cc.put(Constants.DEST_KNOWLEDGE_BASE_ID, c.getDestKnowledgeBaseId()); cc.put(Constants.SOURCE_DOMAIN, c.getSourceDomain()); - cc.put(Constants.SUGGESTED, c.isExtra()); - cc.put(Constants.TO_BE_KEPT, c.isToBeKept()); + // cc.put(Constants.SUGGESTED, c.isExtra()); + // cc.put(Constants.TO_BE_KEPT, c.isToBeKept()); connectionsJson.add(cc); } obj.put(Constants.CONNECTIONS, connectionsJson); @@ -310,14 +310,12 @@ public class Utils { for(SimilarGRSFRecord s: similarRecords){ JSONObject ss = new JSONObject(); ss.put(Constants.KB_ID, s.getKnowledgeBaseId()); - ss.put(Constants.SUGGESTED, s.isExtra()); - ss.put(Constants.TO_BE_KEPT, s.isToBeKept()); ss.put(Constants.MERGE, s.isSuggestedMerge()); similarRecordsJson.add(ss); } obj.put(Constants.SIMILAR_GRSF_RECORDS, similarRecordsJson); - logger.debug("Update request looks like " + obj.toJSONString()); + logger.info("Update request looks like " + obj.toJSONString()); HttpPost request = new HttpPost(serviceUrl + Constants.SERVICE_POST_METHOD); request.setHeader("Accept", "application/json"); @@ -338,6 +336,8 @@ public class Utils { throw new IllegalArgumentException( "Update failed for the following reason " + parsedJSON.get(Constants.ERROR_MESSAGE)); + // send email to VRE administrators and the user as well TODO + }catch(Exception e){ logger.error("Unable to update this Item " + e); throw e; diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/ConnectedBean.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/ConnectedBean.java index f447ed4..f0e5eeb 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/ConnectedBean.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/ConnectedBean.java @@ -16,7 +16,7 @@ public class ConnectedBean implements Serializable{ private String destSemanticIdentifier; private String destKnowledgeBaseId; // the dest indentifier of a Fishery or Stock (the link is from a Stock to a Fishery and viceversa) private String url; - private boolean isExtra; + // private boolean isExtra; private boolean toBeKept = true; public ConnectedBean() { @@ -90,28 +90,42 @@ public class ConnectedBean implements Serializable{ public void setToBeKept(boolean toBeKept) { this.toBeKept = toBeKept; } + // + // public boolean isExtra() { + // return isExtra; + // } + // + // public void setExtra(boolean isExtra) { + // this.isExtra = isExtra; + // } - public boolean isExtra() { - return isExtra; - } - - public void setExtra(boolean isExtra) { - this.isExtra = isExtra; - } - public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } + // @Override + // public String toString() { + // return "ConnectedBean [sourceKnowledgeBaseId=" + sourceKnowledgeBaseId + // + ", sourceDomain=" + sourceDomain + ", destShortName=" + // + destShortName + ", destSemanticIdentifier=" + // + destSemanticIdentifier + ", destKnowledgeBaseId=" + // + destKnowledgeBaseId + ", url=" + url + ", isExtra=" + isExtra + // + ", toBeKept=" + toBeKept + "]"; + // } + @Override public String toString() { return "ConnectedBean [sourceKnowledgeBaseId=" + sourceKnowledgeBaseId + ", sourceDomain=" + sourceDomain + ", destShortName=" + destShortName + ", destSemanticIdentifier=" + destSemanticIdentifier + ", destKnowledgeBaseId=" - + destKnowledgeBaseId + ", url=" + url + ", isExtra=" + isExtra - + ", toBeKept=" + toBeKept + "]"; + + destKnowledgeBaseId + ", url=" + url + ", toBeKept=" + + toBeKept + "]"; } + + + + } diff --git a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/SimilarGRSFRecord.java b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/SimilarGRSFRecord.java index 3147243..11704c0 100644 --- a/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/SimilarGRSFRecord.java +++ b/src/main/java/org/gcube/datacatalogue/grsf_manage_widget/shared/SimilarGRSFRecord.java @@ -16,8 +16,8 @@ public class SimilarGRSFRecord implements Serializable{ private String shortName; private String url; private boolean suggestedMerge; - private boolean isExtra; - private boolean toBeKept = true; + // private boolean isExtra; + // private boolean toBeKept = true; public SimilarGRSFRecord() { super(); @@ -62,13 +62,13 @@ public class SimilarGRSFRecord implements Serializable{ } - public void setToBeKept(boolean toBeKept) { - this.toBeKept = toBeKept; - } - - public boolean isToBeKept() { - return toBeKept; - } + // public void setToBeKept(boolean toBeKept) { + // this.toBeKept = toBeKept; + // } + // + // public boolean isToBeKept() { + // return toBeKept; + // } public String getShortName() { return shortName; @@ -99,21 +99,32 @@ public class SimilarGRSFRecord implements Serializable{ this.suggestedMerge = suggestedMerge; } - public boolean isExtra() { - return isExtra; - } - - public void setExtra(boolean isExtra) { - this.isExtra = isExtra; - } @Override public String toString() { return "SimilarGRSFRecord [description=" + description + ", knowledgeBaseId=" + knowledgeBaseId + ", semanticIdentifier=" + semanticIdentifier + ", shortName=" + shortName + ", url=" + url + ", suggestedMerge=" - + suggestedMerge + ", isExtra=" + isExtra + ", toBeKept=" - + toBeKept + "]"; + + suggestedMerge + "]"; } + // public boolean isExtra() { + // return isExtra; + // } + // + // public void setExtra(boolean isExtra) { + // this.isExtra = isExtra; + // } + // @Override + // public String toString() { + // return "SimilarGRSFRecord [description=" + description + // + ", knowledgeBaseId=" + knowledgeBaseId + // + ", semanticIdentifier=" + semanticIdentifier + ", shortName=" + // + shortName + ", url=" + url + ", suggestedMerge=" + // + suggestedMerge + ", isExtra=" + isExtra + ", toBeKept=" + // + toBeKept + "]"; + // } + + + }