From b0750e783f3931cc6b973d80474849db05c70b2f Mon Sep 17 00:00:00 2001 From: Richard Eckart de Castilho Date: Sat, 5 Aug 2023 10:01:17 +0200 Subject: [PATCH] #4140 - Simplify lazy detail lookup - Remove getLazyDetails() methods that produced the queries - Remove all classes related to the queries - Make lookupLazyDetails produce all the details on the fly when asked for details for a given VID --- .../annotation/page/AnnotationPageBase.java | 3 +- .../preferences/UserPreferencesService.java | 8 +- .../rendering/Renderer_ImplBase.java | 7 -- .../MultiValueStringFeatureSupport.java | 57 +++------ .../feature/string/StringFeatureSupport.java | 43 ++----- .../annotation/layer/chain/ChainRenderer.java | 2 - .../layer/relation/RelationRenderer.java | 37 ++---- .../annotation/layer/span/SpanRenderer.java | 1 - .../editor/AnnotationEditorExtension.java | 9 +- .../rendering/vmodel/VLazyDetailQuery.java | 57 --------- .../rendering/vmodel/VLazyDetailResult.java | 5 +- .../inception/rendering/vmodel/VObject.java | 23 ---- .../ukp/inception/rendering/Renderer.java | 50 ++------ .../schema/AnnotationSchemaService.java | 6 +- .../schema/feature/FeatureSupport.java | 22 +--- .../brat/message/GetDocumentResponse.java | 17 --- .../brat/render/BratSerializerImpl.java | 9 -- .../brat/render/model/Normalization.java | 105 ---------------- .../main/ts/src/visualizer_ui/VisualizerUI.ts | 84 ++----------- .../actions/EditorAjaxRequestHandler.java | 2 - .../LazyDetailsLookupServiceImpl.java | 115 ++++++++++-------- .../src/main/ts/src/diam/DiamAjaxImpl.ts | 6 +- .../feature/lookup/LookupFeatureSupport.java | 38 ++---- .../image/feature/ImageFeatureSupport.java | 27 ++-- .../src/main/ts/src/diam/DiamAjax.ts | 2 +- .../RecommendationEditorExtension.java | 50 +++++--- .../RecommenderServiceAutoConfiguration.java | 5 +- .../RecommendationRelationRenderer.java | 12 -- .../render/RecommendationSpanRenderer.java | 9 -- inception/inception-ui-curation/pom.xml | 29 ++++- .../sidebar/CurationEditorExtension.java | 38 +++++- .../CurationSidebarAutoConfiguration.java | 7 +- .../ui/kb/feature/ConceptFeatureSupport.java | 33 ++--- .../MultiValueConceptFeatureSupport.java | 69 +++-------- 34 files changed, 295 insertions(+), 692 deletions(-) delete mode 100644 inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VLazyDetailQuery.java delete mode 100644 inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/model/Normalization.java diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/page/AnnotationPageBase.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/page/AnnotationPageBase.java index 49e1751c15c..9e53572c3a7 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/page/AnnotationPageBase.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/page/AnnotationPageBase.java @@ -50,7 +50,6 @@ import org.apache.wicket.util.string.StringValueConversionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.BeansException; import org.wicketstuff.urlfragment.UrlFragment; import org.wicketstuff.urlfragment.UrlParametersReceivingBehavior; @@ -423,7 +422,7 @@ public void actionValidateDocument(AjaxRequestTarget aTarget, CAS aCas) * is refreshed based on the visibility preferences and based on the project to which the * document being edited belongs. */ - protected void loadPreferences() throws BeansException, IOException + protected void loadPreferences() throws IOException { AnnotatorState state = getModelObject(); userPreferenceService.loadPreferences(state, userRepository.getCurrentUsername()); diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/preferences/UserPreferencesService.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/preferences/UserPreferencesService.java index 4d274146b10..4d34b975a0d 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/preferences/UserPreferencesService.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/preferences/UserPreferencesService.java @@ -19,8 +19,6 @@ import java.io.IOException; -import org.springframework.beans.BeansException; - import de.tudarmstadt.ukp.clarin.webanno.model.Mode; import de.tudarmstadt.ukp.clarin.webanno.model.Project; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotationPreference; @@ -36,14 +34,10 @@ public interface UserPreferencesService * The {@link AnnotatorState} that will be populated with preferences from the file * @param aUsername * The user for whom we need to read the preference (preferences are stored per user) - * - * @throws BeansException - * hum? * @throws IOException * hum? */ - void loadPreferences(AnnotatorState aState, String aUsername) - throws BeansException, IOException; + void loadPreferences(AnnotatorState aState, String aUsername) throws IOException; AnnotationPreference loadPreferences(Project aProject, String aUsername, Mode aMode) throws IOException; diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/rendering/Renderer_ImplBase.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/rendering/Renderer_ImplBase.java index 84df44f9e31..63186cedcfb 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/rendering/Renderer_ImplBase.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/clarin/webanno/api/annotation/rendering/Renderer_ImplBase.java @@ -29,7 +29,6 @@ import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.inception.rendering.Renderer; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VObject; import de.tudarmstadt.ukp.inception.schema.adapter.TypeAdapter; import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupportRegistry; import de.tudarmstadt.ukp.inception.schema.layer.LayerSupportRegistry; @@ -144,12 +143,6 @@ public Optional getTraits(AnnotationLayer aLayer, Class aInterface) return Optional.empty(); } - public void renderLazyDetails(AnnotationFS fs, VObject aVObject, - List aFeatures) - { - aVObject.addLazyDetails(getLazyDetails(fs, aFeatures)); - } - public abstract List selectAnnotationsInWindow(CAS aCas, int aWindowBegin, int aWindowEnd); } diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/multistring/MultiValueStringFeatureSupport.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/multistring/MultiValueStringFeatureSupport.java index a18fce6abfe..d33115caadd 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/multistring/MultiValueStringFeatureSupport.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/multistring/MultiValueStringFeatureSupport.java @@ -18,8 +18,6 @@ package de.tudarmstadt.ukp.inception.annotation.feature.multistring; import static java.util.Arrays.asList; -import static java.util.Collections.emptyList; -import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.uima.cas.CAS.TYPE_NAME_STRING_ARRAY; @@ -51,8 +49,6 @@ import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState; import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.adapter.IllegalFeatureValueException; @@ -236,43 +232,26 @@ public String renderFeatureValue(AnnotationFeature aFeature, FeatureStructure aF } @Override - public List getLazyDetails(AnnotationFeature aFeature, FeatureStructure aFs) + public List lookupLazyDetails(AnnotationFeature aFeature, Object aValue) { - Feature labelFeature = aFs.getType().getFeatureByBaseName(aFeature.getName()); - - if (labelFeature == null) { - return emptyList(); - } - - List values = getFeatureValue(aFeature, aFs); - if (values == null || values.isEmpty()) { - return emptyList(); - } - - var details = new ArrayList(); - for (String value : values) { - if (isNotBlank(value) && aFeature.getTagset() != null) { - details.add(new VLazyDetailQuery(aFeature.getName(), value)); + var results = new ArrayList(); + if (aValue instanceof Iterable) { + var values = (Iterable) aValue; + for (var v : values) { + if (v instanceof String) { + var value = (String) v; + var tag = schemaService.getTag(value, aFeature.getTagset()); + + if (tag.isEmpty()) { + results.add(new VLazyDetailResult(value, "Tag not in tagset")); + } + + if (tag.map(t -> isNotBlank(t.getDescription())).orElse(false)) { + results.add(new VLazyDetailResult(value, tag.get().getDescription())); + } + } } } - - return details; - } - - @Override - public List renderLazyDetails(CAS aCas, AnnotationFeature aFeature, - VID aParamId, String aQuery) - { - var tag = schemaService.getTag(aQuery, aFeature.getTagset()); - - if (tag.isEmpty()) { - return asList(new VLazyDetailResult(aQuery, "Tag not in tagset")); - } - - if (tag.map(t -> isBlank(t.getDescription())).orElse(true)) { - return emptyList(); - } - - return asList(new VLazyDetailResult(aQuery, tag.get().getDescription())); + return results; } } diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/string/StringFeatureSupport.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/string/StringFeatureSupport.java index e943fea8ed3..1c994bc3295 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/string/StringFeatureSupport.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/feature/string/StringFeatureSupport.java @@ -22,7 +22,7 @@ import static de.tudarmstadt.ukp.inception.annotation.feature.string.StringFeatureTraits.EditorType.RADIOGROUP; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; -import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; import java.io.IOException; import java.util.Collections; @@ -44,8 +44,6 @@ import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState; import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.adapter.AnnotationException; @@ -232,37 +230,20 @@ public boolean suppressAutoFocus(AnnotationFeature aFeature) } @Override - public List getLazyDetails(AnnotationFeature aFeature, String aLabel) + public List lookupLazyDetails(AnnotationFeature aFeature, Object aValue) { - if (isBlank(aLabel) || aFeature.getTagset() == null) { - return emptyList(); - } - - // Checking here if the tag has a description would be nicer because it would avoid - // rendering an emtpy section for every string feature in the popover... but it also - // induces a database request for every single string feature on every annotation which - // would slow things down quite a bit... - // Tag tag = schemaService.getTag(aLabel, aFeature.getTagset()); - // if (tag == null || isBlank(tag.getDescription())) { - // return emptyList(); - // } - - return asList(new VLazyDetailQuery(aFeature.getName(), aLabel)); - } - - @Override - public List renderLazyDetails(CAS aCas, AnnotationFeature aFeature, - VID aParamId, String aQuery) - { - var tag = schemaService.getTag(aQuery, aFeature.getTagset()); - if (tag.isEmpty()) { - return asList(new VLazyDetailResult(aQuery, "Tag not in tagset")); - } + if (aValue instanceof String) { + var value = (String) aValue; + var tag = schemaService.getTag(value, aFeature.getTagset()); + if (tag.isEmpty()) { + return asList(new VLazyDetailResult(value, "Tag not in tagset")); + } - if (tag.map(t -> isBlank(t.getDescription())).orElse(true)) { - return emptyList(); + if (tag.map(t -> isNotBlank(t.getDescription())).orElse(false)) { + return asList(new VLazyDetailResult(value, tag.get().getDescription())); + } } - return asList(new VLazyDetailResult(aQuery, tag.get().getDescription())); + return emptyList(); } } diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/chain/ChainRenderer.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/chain/ChainRenderer.java index 4a5b7e52d34..95a81c14fd1 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/chain/ChainRenderer.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/chain/ChainRenderer.java @@ -170,8 +170,6 @@ public void render(CAS aCas, List aFeatures, VDocument aRespo label); annoToSpanIdx.put(linkFs, span); aResponse.add(span); - - renderLazyDetails(linkFs, span, aFeatures); } // Render arc (we do this on prevLinkFs because then we easily know that the current diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/relation/RelationRenderer.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/relation/RelationRenderer.java index b54f30e70f4..427236b5a77 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/relation/RelationRenderer.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/relation/RelationRenderer.java @@ -55,7 +55,6 @@ import de.tudarmstadt.ukp.inception.rendering.vmodel.VCommentType; import de.tudarmstadt.ukp.inception.rendering.vmodel.VDocument; import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.rendering.vmodel.VObject; import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupportRegistry; @@ -134,12 +133,6 @@ public void render(final CAS aCas, List aFeatures, VDocument RelationAdapter typeAdapter = getTypeAdapter(); - // Map> relationLinks = getRelationLinks(aCas, aWindowBegin, - // aWindowEnd); - // - // // if this is a governor for more than one dependent, avoid duplicate yield - // List yieldDeps = new ArrayList<>(); - // Index mapping annotations to the corresponding rendered arcs Map annoToArcIdx = new HashMap<>(); @@ -154,9 +147,6 @@ public void render(final CAS aCas, List aFeatures, VDocument aResponse.add(arc); annoToArcIdx.put(fs, (VArc) arc); - // renderYield(aResponse, fs, relationLinks, yieldDeps); - - renderLazyDetails(fs, arc, aFeatures); renderRequiredFeatureErrors(aFeatures, fs, aResponse); } } @@ -261,28 +251,17 @@ public List render(VDocument aVDocument, AnnotationFS aFS, } @Override - public List getLazyDetails(AnnotationFS aFs, - List aFeatures) + public List lookupLazyDetails(CAS aCas, VID aVid, int aWindowBeginOffset, + int aWindowEndOffset) { - List queries = super.getLazyDetails(aFs, aFeatures); - - if (!queries.contains(VLazyDetailQuery.LAYER_LEVEL_QUERY)) { - queries.add(VLazyDetailQuery.LAYER_LEVEL_QUERY); + if (!checkTypeSystem(aCas)) { + return Collections.emptyList(); } - return queries; - } - - @Override - public List renderLazyDetails(CAS aCas, VID aVid, int windowBeginOffset, - int windowEndOffset) - { - checkTypeSystem(aCas); - // FIXME Should also handle relations that are only partially visible using // selectAnnotationsInWindow() - Map> relationLinks = getRelationLinks(aCas, windowBeginOffset, - windowEndOffset); + Map> relationLinks = getRelationLinks(aCas, aWindowBeginOffset, + aWindowEndOffset); // if this is a governor for more than one dependent, avoid duplicate yield List yieldDeps = new ArrayList<>(); @@ -291,8 +270,8 @@ public List renderLazyDetails(CAS aCas, VID aVid, int windowB Optional yield = renderYield(fs, relationLinks, yieldDeps); - List details = super.renderLazyDetails(aCas, aVid, windowBeginOffset, - windowEndOffset); + List details = super.lookupLazyDetails(aCas, aVid, aWindowBeginOffset, + aWindowEndOffset); if (yield.isPresent()) { details.add(new VLazyDetailResult("Yield", yield.get())); diff --git a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/span/SpanRenderer.java b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/span/SpanRenderer.java index 050b2d41c57..2c24a6d764f 100644 --- a/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/span/SpanRenderer.java +++ b/inception/inception-api-annotation/src/main/java/de/tudarmstadt/ukp/inception/annotation/layer/span/SpanRenderer.java @@ -121,7 +121,6 @@ public void render(CAS aCas, List aFeatures, VDocument aRespo if (vobj instanceof VSpan) { annoToSpanIdx.put(fs, (VSpan) vobj); - renderLazyDetails(fs, vobj, aFeatures); renderRequiredFeatureErrors(aFeatures, fs, aResponse); } } diff --git a/inception/inception-api-editor/src/main/java/de/tudarmstadt/ukp/inception/editor/AnnotationEditorExtension.java b/inception/inception-api-editor/src/main/java/de/tudarmstadt/ukp/inception/editor/AnnotationEditorExtension.java index b83c17ad486..058a6279556 100644 --- a/inception/inception-api-editor/src/main/java/de/tudarmstadt/ukp/inception/editor/AnnotationEditorExtension.java +++ b/inception/inception-api-editor/src/main/java/de/tudarmstadt/ukp/inception/editor/AnnotationEditorExtension.java @@ -79,9 +79,14 @@ default void generateContextMenuItems(List aItems) // Do nothing by default } - default List renderLazyDetails(SourceDocument aDocument, User aUser, - VID aVid, AnnotationFeature aFeature, String aQuery) + default List lookupLazyDetails(SourceDocument aDocument, User aUser, + VID aVid, AnnotationFeature aFeature) { return Collections.emptyList(); } + + V getFeatureValue(SourceDocument aDocument, User aUser, CAS aCas, VID aVid, + AnnotationFeature aFeature) + throws IOException; + } diff --git a/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VLazyDetailQuery.java b/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VLazyDetailQuery.java deleted file mode 100644 index 3a2b19f5ee9..00000000000 --- a/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VLazyDetailQuery.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Licensed to the Technische Universität Darmstadt under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The Technische Universität Darmstadt - * licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.tudarmstadt.ukp.inception.rendering.vmodel; - -import java.io.Serializable; - -/** - * Query for a lazy detail. - *

- * Some information is only to be shown when the user performs a particular "detail information" - * action, e.g. hovering the mouse over an annotation. This class represents a query which is - * triggered at such a time to load additional information from the server. - *

- * - * @see VLazyDetailResult - */ -public class VLazyDetailQuery - implements Serializable -{ - private static final long serialVersionUID = -3223115878613737370L; - - public static final VLazyDetailQuery LAYER_LEVEL_QUERY = new VLazyDetailQuery(null, null); - - private final String feature; - private final String query; - - public VLazyDetailQuery(String aFeature, String aQuery) - { - feature = aFeature; - query = aQuery; - } - - public String getFeature() - { - return feature; - } - - public String getQuery() - { - return query; - } -} diff --git a/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VLazyDetailResult.java b/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VLazyDetailResult.java index b357c2163ba..d7488289c6d 100644 --- a/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VLazyDetailResult.java +++ b/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VLazyDetailResult.java @@ -23,11 +23,8 @@ * Result for a lazy detail. *

* Some information is only to be shown when the user performs a particular "detail information" - * action, e.g. hovering the mouse over an annotation. This class represents the result which is - * returned by the server for a particular detail query. + * action, e.g. hovering the mouse over an annotation. *

- * - * @see VLazyDetailQuery */ public class VLazyDetailResult implements Serializable diff --git a/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VObject.java b/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VObject.java index 31339ecbea0..28320436fe4 100644 --- a/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VObject.java +++ b/inception/inception-api-render/src/main/java/de/tudarmstadt/ukp/inception/rendering/vmodel/VObject.java @@ -18,9 +18,7 @@ package de.tudarmstadt.ukp.inception.rendering.vmodel; import java.io.Serializable; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; @@ -35,7 +33,6 @@ public abstract class VObject private final int equivalenceSet; private VID vid; - private List lazyDetails = new ArrayList<>(); private String color; private String label; private double score; @@ -80,26 +77,6 @@ public Map getFeatures() return features; } - public List getLazyDetails() - { - return lazyDetails; - } - - public void setLazyDetails(List aLazyDetails) - { - lazyDetails = aLazyDetails; - } - - public void addLazyDetails(List aDetails) - { - lazyDetails.addAll(aDetails); - } - - public void addLazyDetail(VLazyDetailQuery aDetail) - { - lazyDetails.add(aDetail); - } - public void setColorHint(String aColor) { color = aColor; diff --git a/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/rendering/Renderer.java b/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/rendering/Renderer.java index 04084ffdec3..776948201ff 100644 --- a/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/rendering/Renderer.java +++ b/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/rendering/Renderer.java @@ -17,7 +17,6 @@ */ package de.tudarmstadt.ukp.inception.rendering; -import static de.tudarmstadt.ukp.clarin.webanno.model.MultiValueMode.NONE; import static de.tudarmstadt.ukp.clarin.webanno.support.uima.ICasUtil.getAddr; import static de.tudarmstadt.ukp.clarin.webanno.support.uima.ICasUtil.selectByAddr; import static de.tudarmstadt.ukp.inception.schema.validation.ValidationUtils.isRequiredFeatureMissing; @@ -39,7 +38,6 @@ import de.tudarmstadt.ukp.inception.rendering.vmodel.VCommentType; import de.tudarmstadt.ukp.inception.rendering.vmodel.VDocument; import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.rendering.vmodel.VObject; import de.tudarmstadt.ukp.inception.schema.adapter.TypeAdapter; @@ -50,8 +48,6 @@ */ public interface Renderer { - static final String QUERY_LAYER_LEVEL_DETAILS = "#"; - TypeAdapter getTypeAdapter(); /** @@ -98,34 +94,6 @@ default Map renderLabelFeatureValues(TypeAdapter aAdapter, Featu return features; } - default List getLazyDetails(AnnotationFS aFs, - List aFeatures) - { - List details = new ArrayList<>(); - - boolean tiggerLayerLevelLazyDetails = false; - - FeatureSupportRegistry fsr = getFeatureSupportRegistry(); - - for (AnnotationFeature feature : aFeatures) { - if (!feature.isEnabled()) { - continue; - } - - if (feature.isIncludeInHover() && NONE.equals(feature.getMultiValueMode())) { - tiggerLayerLevelLazyDetails = true; - } - - details.addAll(fsr.findExtension(feature).orElseThrow().getLazyDetails(feature, aFs)); - } - - if (tiggerLayerLevelLazyDetails) { - details.add(VLazyDetailQuery.LAYER_LEVEL_QUERY); - } - - return details; - } - default void renderRequiredFeatureErrors(List aFeatures, FeatureStructure aFS, VDocument aResponse) { @@ -141,16 +109,22 @@ default void renderRequiredFeatureErrors(List aFeatures, } } - default List renderLazyDetails(CAS aCas, VID aVid, int windowBeginOffset, + default List lookupLazyDetails(CAS aCas, VID aVid, int windowBeginOffset, int windowEndOffset) { - FeatureSupportRegistry fsr = getFeatureSupportRegistry(); + var fsr = getFeatureSupportRegistry(); - List details = new ArrayList<>(); + var aFs = selectByAddr(aCas, AnnotationFS.class, aVid.getId()); - AnnotationFS aFs = selectByAddr(aCas, AnnotationFS.class, aVid.getId()); + var details = new ArrayList(); + generateLazyDetailsForFeaturesIncludedInHover(fsr, details, aFs); + return details; + } - for (AnnotationFeature feature : getTypeAdapter().listFeatures()) { + default void generateLazyDetailsForFeaturesIncludedInHover(FeatureSupportRegistry fsr, + List details, AnnotationFS aFs) + { + for (var feature : getTypeAdapter().listFeatures()) { if (!feature.isEnabled() || !feature.isIncludeInHover() || !MultiValueMode.NONE.equals(feature.getMultiValueMode())) { continue; @@ -161,7 +135,5 @@ default List renderLazyDetails(CAS aCas, VID aVid, int window details.add(new VLazyDetailResult(feature.getName(), text)); } - - return details; } } diff --git a/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/AnnotationSchemaService.java b/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/AnnotationSchemaService.java index 85b97fbd809..8dcb94edf46 100644 --- a/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/AnnotationSchemaService.java +++ b/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/AnnotationSchemaService.java @@ -273,13 +273,13 @@ public interface AnnotationSchemaService /** * Get an {@link AnnotationFeature} using its name * - * @param name + * @param aFeature * the feature name. - * @param type + * @param aLayer * the feature type. * @return the feature. */ - AnnotationFeature getFeature(String name, AnnotationLayer type); + AnnotationFeature getFeature(String aFeature, AnnotationLayer aLayer); /** * Check if an {@link AnnotationLayer} already exists. diff --git a/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/feature/FeatureSupport.java b/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/feature/FeatureSupport.java index 55d3c9a7e37..3ed8569e0b0 100644 --- a/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/feature/FeatureSupport.java +++ b/inception/inception-api-schema/src/main/java/de/tudarmstadt/ukp/inception/schema/feature/FeatureSupport.java @@ -43,8 +43,6 @@ import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState; import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.adapter.AnnotationException; import de.tudarmstadt.ukp.inception.schema.adapter.TypeAdapter; @@ -221,23 +219,6 @@ default String renderFeatureValue(AnnotationFeature aFeature, FeatureStructure a return renderFeatureValue(aFeature, aFs.getFeatureValueAsString(labelFeature)); } - default List getLazyDetails(AnnotationFeature aFeature, FeatureStructure aFs) - { - Feature labelFeature = aFs.getType().getFeatureByBaseName(aFeature.getName()); - - if (labelFeature != null && labelFeature.getRange().isPrimitive()) { - return getLazyDetails(aFeature, aFs.getFeatureValueAsString(labelFeature)); - } - else { - return Collections.emptyList(); - } - } - - default List getLazyDetails(AnnotationFeature aFeature, String aLabel) - { - return Collections.emptyList(); - } - /** * Gets the label that should be displayed for the given feature value in the UI. {@code null} * is an acceptable return value for this method. @@ -253,8 +234,7 @@ default String renderFeatureValue(AnnotationFeature aFeature, String aLabel) return aLabel; } - default List renderLazyDetails(CAS aCas, AnnotationFeature aFeature, - VID aParamId, String aQuery) + default List lookupLazyDetails(AnnotationFeature aFeature, Object aValue) { return Collections.emptyList(); } diff --git a/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/message/GetDocumentResponse.java b/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/message/GetDocumentResponse.java index 3ffc64e3c48..bfd834a93ca 100644 --- a/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/message/GetDocumentResponse.java +++ b/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/message/GetDocumentResponse.java @@ -30,7 +30,6 @@ import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Comment; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Entity; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Marker; -import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Normalization; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Offsets; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Relation; import de.tudarmstadt.ukp.inception.diam.model.ajax.AjaxResponse; @@ -79,7 +78,6 @@ public class GetDocumentResponse */ private @JsonInclude(NON_EMPTY) List entities = new ArrayList<>(); private @JsonInclude(NON_EMPTY) List comments = new ArrayList<>(); - private @JsonInclude(NON_EMPTY) List normalizations = new ArrayList<>(); private Map> args = new HashMap<>(); @@ -123,21 +121,6 @@ public void addComment(Comment aComment) comments.add(aComment); } - public List getNormalizations() - { - return normalizations; - } - - public void setNormalizations(List aNormalizations) - { - normalizations = aNormalizations; - } - - public void addNormalization(Normalization aNormalization) - { - normalizations.add(aNormalization); - } - public List getTokenOffsets() { return tokenOffsets; diff --git a/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/BratSerializerImpl.java b/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/BratSerializerImpl.java index 677fb851559..5fcc44c337e 100644 --- a/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/BratSerializerImpl.java +++ b/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/BratSerializerImpl.java @@ -47,7 +47,6 @@ import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Argument; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Comment; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Entity; -import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Normalization; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Offsets; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.Relation; import de.tudarmstadt.ukp.clarin.webanno.brat.render.model.SentenceComment; @@ -159,10 +158,6 @@ private void renderLayers(GetDocumentResponse aResponse, VDocument aVDoc) vspan.getRanges().get(vspan.getRanges().size() - 1).isClippedAtEnd()); aResponse.addEntity(entity); - - vspan.getLazyDetails().stream() - .map(d -> new Normalization(vspan.getVid(), d.getFeature(), d.getQuery())) - .forEach(aResponse::addNormalization); } for (VArc varc : aVDoc.arcs(layer.getId())) { @@ -171,10 +166,6 @@ private void renderLayers(GetDocumentResponse aResponse, VDocument aVDoc) getArgument(varc.getSource(), varc.getTarget()), varc.getLabelHint(), varc.getColorHint()); aResponse.addRelation(arc); - - varc.getLazyDetails().stream() - .map(d -> new Normalization(varc.getVid(), d.getFeature(), d.getQuery())) - .forEach(aResponse::addNormalization); } } } diff --git a/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/model/Normalization.java b/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/model/Normalization.java deleted file mode 100644 index e5866cfe1f4..00000000000 --- a/inception/inception-brat-editor/src/main/java/de/tudarmstadt/ukp/clarin/webanno/brat/render/model/Normalization.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Licensed to the Technische Universität Darmstadt under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The Technische Universität Darmstadt - * licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package de.tudarmstadt.ukp.clarin.webanno.brat.render.model; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; -import static org.apache.commons.lang3.StringUtils.defaultIfEmpty; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonPropertyOrder; -import com.fasterxml.jackson.databind.annotation.JsonSerialize; - -import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.support.json.BeanAsArraySerializer; - -@JsonSerialize(using = BeanAsArraySerializer.class) -@JsonPropertyOrder(value = { "target", "refDb", "refId", "refText" }) -public class Normalization -{ - private VID target; - - @JsonInclude(NON_NULL) - private String refDb; - - @JsonInclude(NON_NULL) - private String refId; - - // If the refText is set, no AJAX query is performed. This is a behavior modification in the - // JS code by us - // NOTE: If refText is set, then refId **MUST** also be set! - @JsonInclude(NON_NULL) - private String refText; - - public Normalization(VID aTarget, String aReftext) - { - this(aTarget, "", "", aReftext); - } - - public Normalization(VID aTarget, String aRefDb, String aRefId) - { - this(aTarget, aRefDb, defaultIfEmpty(aRefId, null), null); - } - - public Normalization(VID aTarget, String aRefDb, String aRefId, String aReftext) - { - target = aTarget; - refText = aReftext; - refDb = aRefDb; - refId = aRefId; - } - - public VID getTarget() - { - return target; - } - - public void setTarget(VID aTarget) - { - target = aTarget; - } - - public String getRefDb() - { - return refDb; - } - - public void setRefDb(String aRefDb) - { - refDb = aRefDb; - } - - public String getRefId() - { - return refId; - } - - public void setRefId(String aRefId) - { - refId = aRefId; - } - - public String getReftext() - { - return refText; - } - - public void setReftext(String aReftext) - { - refText = aReftext; - } -} diff --git a/inception/inception-brat-editor/src/main/ts/src/visualizer_ui/VisualizerUI.ts b/inception/inception-brat-editor/src/main/ts/src/visualizer_ui/VisualizerUI.ts index 01e083eb9c5..e40a6c3941d 100644 --- a/inception/inception-brat-editor/src/main/ts/src/visualizer_ui/VisualizerUI.ts +++ b/inception/inception-brat-editor/src/main/ts/src/visualizer_ui/VisualizerUI.ts @@ -60,7 +60,7 @@ export class VisualizerUI { private commentPopup: JQuery private commentDisplayed = false - private displayCommentTimer = null + private displayCommentTimer: number | undefined = undefined private ajax: DiamAjax @@ -78,7 +78,6 @@ export class VisualizerUI { .on('displaySentComment', this, this.displaySentComment) .on('hideComment', this, this.hideComment) .on('resize', this, this.onResize) - .on('collectionLoaded', this, this.rememberNormDb) .on('spanAndAttributeTypesLoaded', this, this.spanAndAttributeTypesLoaded) .on('doneRendering', this, this.onDoneRendering) .on('mousemove', this, this.onMouseMove) @@ -177,15 +176,13 @@ export class VisualizerUI { comment += ('
"' + Util.escapeHTML(spanText) + '"
') } - // process normalizations - const normsToQuery = [] - comment += this.processNormalizations(normalizations, normsToQuery) + comment += '
' // display initial comment HTML this.displayComment(evt, comment, commentText, commentType, immediately) // initiate AJAX calls for the normalization data to query - $.each(normsToQuery, (normNo, norm) => this.initiateNormalizationAjaxCall(spanId, spanType, norm)) + this.initiateNormalizationAjaxCall(spanId, spanType) } displayArcComment (evt, target, symmetric, arcId, originSpanId, originSpanType, @@ -200,65 +197,17 @@ export class VisualizerUI { '' + (arcId ? 'ID:' + arcId : Util.escapeHTML(originSpanId) + arrowStr + Util.escapeHTML(targetSpanId)) + '' + '') comment += ('
' + Util.escapeHTML('"' + this.data.spans[originSpanId].text + '"') + arrowStr + Util.escapeHTML('"' + this.data.spans[targetSpanId].text + '"') + '
') - - // process normalizations - const normsToQuery = [] - comment += this.processNormalizations(normalizations, normsToQuery) + comment += '
' this.displayComment(evt, comment, commentText, commentType) // initiate AJAX calls for the normalization data to query - $.each(normsToQuery, (normNo, norm) => this.initiateNormalizationAjaxCall(arcId, arcRole, norm)) - } - - processNormalizations (normalizations, normsToQuery) { - let comment = '' - $.each(normalizations != null ? normalizations : [], (normNo, norm) => { - if (norm[2]) { - const cateogory = norm[0] - const key = norm[1] - const value = norm[2] - // no DB, just attach "human-readable" text provided with the annotation, if any - if (cateogory) { - comment += `
- ${Util.escapeHTML(cateogory)}' - ` - } - - if (key) { - comment += `${Util.escapeHTML(key)} - ` - } - - comment += `${Util.escapeHTML(value)?.replace(/\n/g, '
')}
-
- ` - } else { - // DB available, add drop-off point to HTML and store query parameters - const dbName = norm[0] - const dbKey = norm[1] - this.commentPopupNormInfoSeqId++ - if (dbKey) { - comment += `
- ${Util.escapeHTML(dbName)}: ${Util.escapeHTML(dbKey)} -
` - } else { - comment += '
' - } - comment += `
` - normsToQuery.push([dbName, dbKey, this.commentPopupNormInfoSeqId]) - } - }) - return comment.replace(/^\s*/gm, '') + this.initiateNormalizationAjaxCall(arcId, arcRole) } - initiateNormalizationAjaxCall (id, type, normq) { + initiateNormalizationAjaxCall (id, type) { // TODO: cache some number of most recent norm_get_data results - const dbName = normq[0] - const dbKey = normq[1] - const infoSeqId = normq[2] - - this.ajax.loadLazyDetails(id, type, dbName, dbKey).then(response => { + this.ajax.loadLazyDetails(id, type).then(response => { if (response.exception) { // TODO: response to error } else if (!response.results) { @@ -297,11 +246,12 @@ export class VisualizerUI { } } } - const drop = $('#norm_info_drop_point_' + infoSeqId) + + const drop = $('#lazy_details_drop_point') if (drop) { drop.html(norminfo) } else { - console.log('norm info drop point not found!') // TODO XXX + console.log('Lazy details drop point not found!') // TODO XXX } } }) @@ -333,7 +283,7 @@ export class VisualizerUI { /* END comment popup - related */ // BEGIN WEBANNO EXTENSION - #1697 - Explicit UI for accepting/recejcting recommendations - displayButtonsTimer = null + displayButtonsTimer: number | undefined = undefined buttonsShown = false acceptAction (evt: MouseEvent, offsets, editedSpan, id) { evt.preventDefault() @@ -420,18 +370,6 @@ export class VisualizerUI { /* START form management - related */ - rememberNormDb (response) { - // the visualizer needs to remember aspects of the norm setup - // so that it can avoid making queries for unconfigured or - // missing normalization DBs. - const norm_resources = response.normalization_config || [] - $.each(norm_resources, (normNo, norm) => { - const normName = norm[0] - const serverDb = norm[3] - this.normServerDbByNormDbName[normName] = serverDb - }) - } - onDoneRendering (args) { if (args && !args.edited) { // FIXME REC 2021-11-21 - Good idea but won't work in INCEpTION since there could diff --git a/inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/editor/actions/EditorAjaxRequestHandler.java b/inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/editor/actions/EditorAjaxRequestHandler.java index f21f5effcdc..13050ed5660 100644 --- a/inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/editor/actions/EditorAjaxRequestHandler.java +++ b/inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/editor/actions/EditorAjaxRequestHandler.java @@ -42,8 +42,6 @@ public interface EditorAjaxRequestHandler String PARAM_TARGET_SPAN_ID = "targetSpanId"; String PARAM_ORIGIN_SPAN_ID = "originSpanId"; String PARAM_TYPE = "type"; - String PARAM_LAZY_DETAIL_DATABASE = "database"; - String PARAM_LAZY_DETAIL_KEY = "key"; String ACTION_CONTEXT_MENU = "contextMenu"; diff --git a/inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/editor/lazydetails/LazyDetailsLookupServiceImpl.java b/inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/editor/lazydetails/LazyDetailsLookupServiceImpl.java index cab095e0be0..fbd25d52609 100644 --- a/inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/editor/lazydetails/LazyDetailsLookupServiceImpl.java +++ b/inception/inception-diam/src/main/java/de/tudarmstadt/ukp/inception/diam/editor/lazydetails/LazyDetailsLookupServiceImpl.java @@ -17,16 +17,17 @@ */ package de.tudarmstadt.ukp.inception.diam.editor.lazydetails; -import static de.tudarmstadt.ukp.inception.diam.editor.actions.EditorAjaxRequestHandler.PARAM_LAZY_DETAIL_DATABASE; -import static de.tudarmstadt.ukp.inception.diam.editor.actions.EditorAjaxRequestHandler.PARAM_LAZY_DETAIL_KEY; +import static de.tudarmstadt.ukp.clarin.webanno.support.uima.ICasUtil.selectFsByAddr; import static de.tudarmstadt.ukp.inception.diam.editor.actions.EditorAjaxRequestHandler.PARAM_TYPE; import static de.tudarmstadt.ukp.inception.diam.editor.actions.LazyDetailsHandler.COMMAND; +import static java.util.Collections.emptyList; import static java.util.stream.Collectors.toList; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import org.apache.uima.cas.CAS; import org.apache.wicket.request.IRequestParameters; import org.apache.wicket.util.string.StringValue; @@ -38,7 +39,6 @@ import de.tudarmstadt.ukp.clarin.webanno.security.model.User; import de.tudarmstadt.ukp.inception.diam.editor.config.DiamAutoConfig; import de.tudarmstadt.ukp.inception.editor.AnnotationEditorExtensionRegistry; -import de.tudarmstadt.ukp.inception.rendering.Renderer; import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.AnnotationSchemaService; @@ -71,42 +71,35 @@ public LazyDetailsLookupServiceImpl(AnnotationSchemaService aAnnotationService, } @Override - public LazyDetailsResponse lookupLazyDetails(IRequestParameters request, VID paramId, + public LazyDetailsResponse lookupLazyDetails(IRequestParameters request, VID aVid, CasProvider aCas, SourceDocument aDocument, User aUser, int windowBeginOffset, int windowEndOffset) throws AnnotationException, IOException { - LazyDetailsResponse response = new LazyDetailsResponse(COMMAND); + var response = new LazyDetailsResponse(COMMAND); - var topicParam = request.getParameterValue(PARAM_LAZY_DETAIL_DATABASE); - var keyParam = request.getParameterValue(PARAM_LAZY_DETAIL_KEY); var layerParam = request.getParameterValue(PARAM_TYPE); - if (layerParam.isEmpty() || topicParam.isEmpty()) { + if (layerParam.isEmpty()) { return response; } - Project project = aDocument.getProject(); - String topic = topicParam.toString(); - long layerId = layerParam.toLong(); - AnnotationLayer layer = annotationService.getLayer(project, layerId) - .orElseThrow(() -> new AnnotationException( - "Layer with ID [" + layerId + "] does not exist in project " + project)); + var cas = aCas.get(); + var layer = findLayer(aVid, cas, layerParam, aDocument.getProject()); - List details = new ArrayList<>(); + var details = new ArrayList(); - renderExtensionLevelDetail(paramId, aDocument, aUser, keyParam, topic, layer, details); + lookupLayerLevelDetails(aVid, cas, windowBeginOffset, windowEndOffset, layer) + .forEach(details::add); - // Is it a layer-level lazy detail? - if (Renderer.QUERY_LAYER_LEVEL_DETAILS.equals(topic)) { - renderLayerLevelDetail(paramId, aCas, windowBeginOffset, windowEndOffset, layer, - details); - } - // Is it a feature-level lazy detail? - // We interpret the key as the feature value or as a kind of query to be handled by the - // feature support - else if (!keyParam.isEmpty()) { - renderFeatureLevelDetail(paramId, aCas, keyParam, topic, layer, details); + for (var feature : annotationService.listAnnotationFeature(layer)) { + lookupExtensionLevelDetails(aVid, aDocument, cas, aUser, feature).forEach(details::add); + + // FIXME: We would like to get feature-level lazy details for the annotation label + // provided by the extension or said otherwise, we want to e.g. get KB details for a + // concept + // feature suggestion... this worked when we used the "query", but now is broken! + lookupFeatureLevelDetail(aVid, cas, feature).forEach(details::add); } response.setResults(details.stream() // @@ -116,41 +109,59 @@ else if (!keyParam.isEmpty()) { return response; } - private void renderFeatureLevelDetail(VID paramId, CasProvider aCas, StringValue keyParam, - String topic, AnnotationLayer layer, List details) - throws IOException + private AnnotationLayer findLayer(VID aVid, CAS aCas, StringValue aLayerParam, Project project) + throws AnnotationException, IOException { - AnnotationFeature feature = annotationService.getFeature(topic, layer); - featureSupportRegistry.findExtension(feature).orElseThrow() - .renderLazyDetails(aCas.get(), feature, paramId, keyParam.toString()) // - .forEach(details::add); + if (aVid.isSynthetic()) { + var layerId = aLayerParam.toLong(); + return annotationService.getLayer(project, layerId) + .orElseThrow(() -> new AnnotationException("Layer with ID [" + layerId + + "] does not exist in project " + project)); + } + + var fs = selectFsByAddr(aCas, aVid.getId()); + return annotationService.findLayer(project, fs); } - private void renderLayerLevelDetail(VID paramId, CasProvider aCas, int windowBeginOffset, - int windowEndOffset, AnnotationLayer layer, List details) - throws IOException + private List lookupFeatureLevelDetail(VID aVid, CAS aCas, + AnnotationFeature aFeature) { - layerSupportRegistry.getLayerSupport(layer) - .createRenderer(layer, () -> annotationService.listAnnotationFeature(layer)) - .renderLazyDetails(aCas.get(), paramId, windowBeginOffset, windowEndOffset) - .forEach(details::add); + if (aVid.isSynthetic()) { + return emptyList(); + } + + var fs = selectFsByAddr(aCas, aVid.getId()); + var ext = featureSupportRegistry.findExtension(aFeature).orElseThrow(); + return ext.lookupLazyDetails(aFeature, ext.getFeatureValue(aFeature, fs)); } - private void renderExtensionLevelDetail(VID paramId, SourceDocument aSourceDocument, User aUser, - StringValue keyParam, String topic, AnnotationLayer layer, - List details) + private List lookupLayerLevelDetails(VID aVid, CAS aCas, + int windowBeginOffset, int windowEndOffset, AnnotationLayer aLayer) { - // Only applies to synthetic annotations (i.e. from extensions) - if (!paramId.isSynthetic()) { - return; + if (aVid.isSynthetic()) { + return emptyList(); } - AnnotationFeature feature = annotationService.getFeature(topic, layer); + return layerSupportRegistry.getLayerSupport(aLayer) + .createRenderer(aLayer, () -> annotationService.listAnnotationFeature(aLayer)) + .lookupLazyDetails(aCas, aVid, windowBeginOffset, windowEndOffset); - String extensionId = paramId.getExtensionId(); - extensionRegistry.getExtension(extensionId) - .renderLazyDetails(aSourceDocument, aUser, paramId, feature, - keyParam.toOptionalString()) // - .forEach(details::add); + } + + private List lookupExtensionLevelDetails(VID aVid, SourceDocument aDocument, + CAS aCas, User aUser, AnnotationFeature aFeature) + throws IOException + { + if (!aVid.isSynthetic()) { + return emptyList(); + } + + var result = new ArrayList(); + var extension = extensionRegistry.getExtension(aVid.getExtensionId()); + var value = extension.getFeatureValue(aDocument, aUser, aCas, aVid, aFeature); + featureSupportRegistry.findExtension(aFeature).orElseThrow() + .lookupLazyDetails(aFeature, value).forEach(result::add); + extension.lookupLazyDetails(aDocument, aUser, aVid, aFeature).forEach(result::add); + return result; } } diff --git a/inception/inception-diam/src/main/ts/src/diam/DiamAjaxImpl.ts b/inception/inception-diam/src/main/ts/src/diam/DiamAjaxImpl.ts index acec99eba1e..731b4b2adfe 100644 --- a/inception/inception-diam/src/main/ts/src/diam/DiamAjaxImpl.ts +++ b/inception/inception-diam/src/main/ts/src/diam/DiamAjaxImpl.ts @@ -229,16 +229,14 @@ export class DiamAjaxImpl implements DiamAjax { }) } - loadLazyDetails (id: VID, type: string, database: string, key: string): Promise { + loadLazyDetails (id: VID, type: string): Promise { const token = DiamAjaxImpl.newToken() const params: Record = { action: 'normData', token, id, - type, - database, - key + type } return new Promise((resolve, reject) => { diff --git a/inception/inception-feature-lookup/src/main/java/de/tudarmstadt/ukp/inception/feature/lookup/LookupFeatureSupport.java b/inception/inception-feature-lookup/src/main/java/de/tudarmstadt/ukp/inception/feature/lookup/LookupFeatureSupport.java index d54e481b12d..42ef6a0a6cb 100644 --- a/inception/inception-feature-lookup/src/main/java/de/tudarmstadt/ukp/inception/feature/lookup/LookupFeatureSupport.java +++ b/inception/inception-feature-lookup/src/main/java/de/tudarmstadt/ukp/inception/feature/lookup/LookupFeatureSupport.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; import org.apache.uima.cas.CAS; import org.apache.uima.resource.metadata.TypeDescription; import org.apache.uima.resource.metadata.TypeSystemDescription; @@ -44,8 +43,6 @@ import de.tudarmstadt.ukp.inception.feature.lookup.config.LookupServiceProperties; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState; import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.feature.FeatureEditor; import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupport; @@ -236,32 +233,23 @@ public void generateFeature(TypeSystemDescription aTSD, TypeDescription aTD, { aTD.addFeature(aFeature.getName(), "", CAS.TYPE_NAME_STRING); } - - @Override - public List getLazyDetails(AnnotationFeature aFeature, String aLabel) - { - if (StringUtils.isEmpty(aLabel)) { - return Collections.emptyList(); - } - - return asList(new VLazyDetailQuery(aFeature.getName(), aLabel)); - } - + @Override - public List renderLazyDetails(CAS aCas, AnnotationFeature aFeature, - VID aParamId, String aQuery) + public List lookupLazyDetails(AnnotationFeature aFeature, Object aValue) { - List result = new ArrayList<>(); - - LookupFeatureTraits traits = readTraits(aFeature); - LookupEntry handle = labelCache.get(aFeature, traits, aQuery); + if (aValue instanceof LookupEntry) { + var handle = (LookupEntry) aValue; + + var result = new ArrayList(); + result.add(new VLazyDetailResult("Label", handle.getUiLabel())); - result.add(new VLazyDetailResult("Label", handle.getUiLabel())); + if (isNotBlank(handle.getDescription())) { + result.add(new VLazyDetailResult("Description", handle.getDescription())); + } - if (isNotBlank(handle.getDescription())) { - result.add(new VLazyDetailResult("Description", handle.getDescription())); + return result; } - - return result; + + return Collections.emptyList(); } } diff --git a/inception/inception-image/src/main/java/de/tudarmstadt/ukp/inception/image/feature/ImageFeatureSupport.java b/inception/inception-image/src/main/java/de/tudarmstadt/ukp/inception/image/feature/ImageFeatureSupport.java index ac3b36c91ca..853e77fa916 100644 --- a/inception/inception-image/src/main/java/de/tudarmstadt/ukp/inception/image/feature/ImageFeatureSupport.java +++ b/inception/inception-image/src/main/java/de/tudarmstadt/ukp/inception/image/feature/ImageFeatureSupport.java @@ -18,6 +18,8 @@ package de.tudarmstadt.ukp.inception.image.feature; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; +import static org.apache.commons.lang3.StringUtils.isBlank; import java.io.IOException; import java.io.Serializable; @@ -25,9 +27,7 @@ import java.util.List; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; import org.apache.uima.cas.CAS; -import org.apache.uima.cas.FeatureStructure; import org.apache.uima.resource.metadata.TypeDescription; import org.apache.uima.resource.metadata.TypeSystemDescription; import org.apache.wicket.MarkupContainer; @@ -44,8 +44,6 @@ import de.tudarmstadt.ukp.inception.image.config.ImageSupportAutoConfiguration; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState; import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.feature.FeatureEditor; import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupport; @@ -199,21 +197,18 @@ public Serializable wrapFeatureValue(AnnotationFeature aFeature, CAS aCAS, Objec } @Override - public List getLazyDetails(AnnotationFeature aFeature, FeatureStructure aFs) + public List lookupLazyDetails(AnnotationFeature aFeature, Object aValue) { - String label = renderFeatureValue(aFeature, aFs); + if (aValue instanceof String) { + var url = (String) aValue; - if (StringUtils.isEmpty(label)) { - return Collections.emptyList(); - } + if (isBlank(url)) { + return emptyList(); + } - return asList(new VLazyDetailQuery(aFeature.getName(), label)); - } + return asList(new VLazyDetailResult("", url)); + } - @Override - public List renderLazyDetails(CAS aCas, AnnotationFeature aFeature, - VID aParamId, String aQuery) - { - return asList(new VLazyDetailResult("", aQuery)); + return Collections.emptyList(); } } diff --git a/inception/inception-js-api/src/main/ts/src/diam/DiamAjax.ts b/inception/inception-js-api/src/main/ts/src/diam/DiamAjax.ts index a005ed454e6..582145d1b77 100644 --- a/inception/inception-js-api/src/main/ts/src/diam/DiamAjax.ts +++ b/inception/inception-js-api/src/main/ts/src/diam/DiamAjax.ts @@ -49,7 +49,7 @@ export interface DiamAjax { loadAnnotations(options?: DiamLoadAnnotationsOptions): Promise; - loadLazyDetails(id: VID, type: string, database: string, key: string): Promise; + loadLazyDetails(id: VID, type: string): Promise; loadPreferences (key: string): Promise; diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/RecommendationEditorExtension.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/RecommendationEditorExtension.java index de66ed47c9a..c7e4e949d7b 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/RecommendationEditorExtension.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/RecommendationEditorExtension.java @@ -39,7 +39,6 @@ import org.apache.wicket.feedback.IFeedback; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import de.tudarmstadt.ukp.clarin.webanno.api.annotation.page.AnnotationPageBase; @@ -61,10 +60,8 @@ import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService; import de.tudarmstadt.ukp.inception.recommendation.api.model.AnnotationSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.Predictions; -import de.tudarmstadt.ukp.inception.recommendation.api.model.Preferences; import de.tudarmstadt.ukp.inception.recommendation.api.model.RelationSuggestion; import de.tudarmstadt.ukp.inception.recommendation.api.model.SpanSuggestion; -import de.tudarmstadt.ukp.inception.recommendation.api.model.SuggestionGroup; import de.tudarmstadt.ukp.inception.recommendation.config.RecommenderServiceAutoConfiguration; import de.tudarmstadt.ukp.inception.recommendation.event.AjaxRecommendationAcceptedEvent; import de.tudarmstadt.ukp.inception.recommendation.event.AjaxRecommendationRejectedEvent; @@ -75,6 +72,7 @@ import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.adapter.AnnotationException; +import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupportRegistry; /** * This component hooks into the annotation editor in order to: @@ -101,16 +99,18 @@ public class RecommendationEditorExtension private final RecommendationService recommendationService; private final ApplicationEventPublisher applicationEventPublisher; private final UserDao userService; + private final FeatureSupportRegistry featureSupportRegistry; - @Autowired public RecommendationEditorExtension(AnnotationSchemaService aAnnotationService, RecommendationService aRecommendationService, - ApplicationEventPublisher aApplicationEventPublisher, UserDao aUserRegistry) + ApplicationEventPublisher aApplicationEventPublisher, UserDao aUserRegistry, + FeatureSupportRegistry aFeatureSupportRegistry) { annotationService = aAnnotationService; recommendationService = aRecommendationService; applicationEventPublisher = aApplicationEventPublisher; userService = aUserRegistry; + featureSupportRegistry = aFeatureSupportRegistry; } @Override @@ -328,16 +328,35 @@ public void renderRequested(AjaxRequestTarget aTarget, AnnotatorState aState) } @Override - public List renderLazyDetails(SourceDocument aDocument, User aUser, VID aVid, - AnnotationFeature aFeature, String aQuery) + @SuppressWarnings("unchecked") + public V getFeatureValue(SourceDocument aDocument, User aUser, CAS aCas, VID aVid, + AnnotationFeature aFeature) { var predictions = recommendationService.getPredictions(aUser, aDocument.getProject()); if (predictions == null) { - return emptyList(); + return null; + } + + var vid = VID.parse(aVid.getExtensionPayload()); + var ao = predictions.getPredictionByVID(aDocument, vid); + if (ao.isEmpty() || !ao.get().getFeature().equals(aFeature.getName())) { + return null; } - Preferences pref = recommendationService.getPreferences(aUser, aDocument.getProject()); + return (V) featureSupportRegistry.findExtension(aFeature) + .map(ext -> ext.wrapFeatureValue(aFeature, aCas, ao.get().getLabel())).orElse(null); + } + + @Override + public List lookupLazyDetails(SourceDocument aDocument, User aUser, VID aVid, + AnnotationFeature aFeature) + { + var predictions = recommendationService.getPredictions(aUser, aDocument.getProject()); + + if (predictions == null) { + return emptyList(); + } var vid = VID.parse(aVid.getExtensionPayload()); var representative = predictions.getPredictionByVID(aDocument, vid); @@ -345,8 +364,8 @@ public List renderLazyDetails(SourceDocument aDocument, User return emptyList(); } - AnnotationSuggestion sao = representative.get(); - Optional> group = predictions + var sao = representative.get(); + var group = predictions .getGroupedPredictions(AnnotationSuggestion.class, aDocument.getName(), aFeature.getLayer(), sao.getWindowBegin(), sao.getWindowEnd()) .stream() // @@ -357,13 +376,14 @@ public List renderLazyDetails(SourceDocument aDocument, User return emptyList(); } - var label = defaultIfBlank(aQuery, null); + var pref = recommendationService.getPreferences(aUser, aDocument.getProject()); + var label = defaultIfBlank(sao.getLabel(), null); var sortedByScore = group.get().bestSuggestionsByFeatureAndLabel(pref, aFeature.getName(), label); - List details = new ArrayList<>(); - for (AnnotationSuggestion ao : sortedByScore) { - List items = new ArrayList<>(); + var details = new ArrayList(); + for (var ao : sortedByScore) { + var items = new ArrayList(); if (ao.getScore() != -1) { items.add(String.format("Score: %.2f", ao.getScore())); } diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/config/RecommenderServiceAutoConfiguration.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/config/RecommenderServiceAutoConfiguration.java index e2c5c013e97..5f9affbb892 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/config/RecommenderServiceAutoConfiguration.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/config/RecommenderServiceAutoConfiguration.java @@ -160,10 +160,11 @@ public RecommendationSidebarFactory recommendationSidebarFactory( public RecommendationEditorExtension recommendationEditorExtension( AnnotationSchemaService aAnnotationService, RecommendationService aRecommendationService, - ApplicationEventPublisher aApplicationEventPublisher, UserDao aUserService) + ApplicationEventPublisher aApplicationEventPublisher, UserDao aUserService, + FeatureSupportRegistry aFeatureSupportRegistry) { return new RecommendationEditorExtension(aAnnotationService, aRecommendationService, - aApplicationEventPublisher, aUserService); + aApplicationEventPublisher, aUserService, aFeatureSupportRegistry); } @Bean diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/render/RecommendationRelationRenderer.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/render/RecommendationRelationRenderer.java index 93b032c9122..255b7d14748 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/render/RecommendationRelationRenderer.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/render/RecommendationRelationRenderer.java @@ -23,7 +23,6 @@ import static java.util.stream.Collectors.toMap; import static org.apache.uima.fit.util.CasUtil.selectAt; -import java.util.List; import java.util.Map; import org.apache.uima.cas.Type; @@ -43,7 +42,6 @@ import de.tudarmstadt.ukp.inception.rendering.vmodel.VArc; import de.tudarmstadt.ukp.inception.rendering.vmodel.VDocument; import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.schema.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupport; import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupportRegistry; @@ -148,16 +146,6 @@ public void render(VDocument aVDoc, RenderRequest aRequest, Predictions aPredict "\uD83E\uDD16 " + suggestion.getUiLabel(), featureAnnotation, COLOR); arc.setScore(suggestion.getScore()); - List lazyDetails = featureSupport.getLazyDetails(feature, - suggestion.getLabel()); - if (!lazyDetails.isEmpty()) { - arc.addLazyDetails(lazyDetails); - } - else { - arc.addLazyDetail( - new VLazyDetailQuery(feature.getName(), suggestion.getLabel())); - } - aVDoc.add(arc); } } diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/render/RecommendationSpanRenderer.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/render/RecommendationSpanRenderer.java index 59250262805..c471615d4cd 100644 --- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/render/RecommendationSpanRenderer.java +++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/render/RecommendationSpanRenderer.java @@ -33,7 +33,6 @@ import de.tudarmstadt.ukp.inception.recommendation.config.RecommenderServiceAutoConfiguration; import de.tudarmstadt.ukp.inception.rendering.request.RenderRequest; import de.tudarmstadt.ukp.inception.rendering.vmodel.VDocument; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VRange; import de.tudarmstadt.ukp.inception.rendering.vmodel.VSpan; import de.tudarmstadt.ukp.inception.schema.AnnotationSchemaService; @@ -126,14 +125,6 @@ public void render(VDocument vdoc, RenderRequest aRequest, Predictions aPredicti v.setScore(suggestion.getScore()); v.setActionButtons(recommenderProperties.isActionButtonsEnabled()); - var lazyDetails = featureSupport.getLazyDetails(feature, suggestion.getLabel()); - if (!lazyDetails.isEmpty()) { - v.addLazyDetails(lazyDetails); - } - else { - v.addLazyDetail(new VLazyDetailQuery(feature.getName(), suggestion.getLabel())); - } - vdoc.add(v); } } diff --git a/inception/inception-ui-curation/pom.xml b/inception/inception-ui-curation/pom.xml index 17c069ea55d..bec746617a5 100644 --- a/inception/inception-ui-curation/pom.xml +++ b/inception/inception-ui-curation/pom.xml @@ -15,7 +15,9 @@ See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 de.tudarmstadt.ukp.inception.app @@ -120,11 +122,11 @@ org.springframework - spring-tx + spring-beans org.springframework - spring-beans + spring-tx org.springframework @@ -214,13 +216,12 @@ org.slf4j slf4j-api - + javax.persistence javax.persistence-api - - + org.springframework.boot spring-boot-starter-data-jpa @@ -242,4 +243,20 @@ test + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.springframework:spring-beans + + + + + + \ No newline at end of file diff --git a/inception/inception-ui-curation/src/main/java/de/tudarmstadt/ukp/inception/ui/curation/sidebar/CurationEditorExtension.java b/inception/inception-ui-curation/src/main/java/de/tudarmstadt/ukp/inception/ui/curation/sidebar/CurationEditorExtension.java index cf93a9e6388..121ebfd8f7b 100644 --- a/inception/inception-ui-curation/src/main/java/de/tudarmstadt/ukp/inception/ui/curation/sidebar/CurationEditorExtension.java +++ b/inception/inception-ui-curation/src/main/java/de/tudarmstadt/ukp/inception/ui/curation/sidebar/CurationEditorExtension.java @@ -27,7 +27,6 @@ import org.apache.wicket.ajax.AjaxRequestTarget; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import de.tudarmstadt.ukp.clarin.webanno.api.DocumentService; @@ -37,6 +36,7 @@ import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer; import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument; import de.tudarmstadt.ukp.clarin.webanno.security.UserDao; +import de.tudarmstadt.ukp.clarin.webanno.security.model.User; import de.tudarmstadt.ukp.clarin.webanno.support.uima.ICasUtil; import de.tudarmstadt.ukp.inception.curation.merge.CasMerge; import de.tudarmstadt.ukp.inception.curation.merge.CasMergeOperationResult; @@ -50,6 +50,7 @@ import de.tudarmstadt.ukp.inception.schema.AnnotationSchemaService; import de.tudarmstadt.ukp.inception.schema.adapter.AnnotationException; import de.tudarmstadt.ukp.inception.schema.adapter.TypeAdapter; +import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupportRegistry; import de.tudarmstadt.ukp.inception.ui.curation.sidebar.config.CurationSidebarAutoConfiguration; import de.tudarmstadt.ukp.inception.ui.curation.sidebar.render.CurationVID; @@ -72,17 +73,19 @@ public class CurationEditorExtension private final ApplicationEventPublisher applicationEventPublisher; private final UserDao userRepository; private final CurationSidebarService curationSidebarService; + private final FeatureSupportRegistry featureSupportRegistry; - @Autowired public CurationEditorExtension(AnnotationSchemaService aAnnotationService, DocumentService aDocumentService, ApplicationEventPublisher aApplicationEventPublisher, - UserDao aUserRepository, CurationSidebarService aCurationSidebarService) + UserDao aUserRepository, CurationSidebarService aCurationSidebarService, + FeatureSupportRegistry aFeatureSupportRegistry) { annotationService = aAnnotationService; documentService = aDocumentService; applicationEventPublisher = aApplicationEventPublisher; userRepository = aUserRepository; curationSidebarService = aCurationSidebarService; + featureSupportRegistry = aFeatureSupportRegistry; } @Override @@ -136,6 +139,35 @@ else if (ScrollToHandler.COMMAND.equals(aAction)) { } } + @Override + public V getFeatureValue(SourceDocument aDocument, User aUser, CAS aCas, VID aVid, + AnnotationFeature aFeature) + throws IOException + { + // only process actions relevant to curation + if (!aVid.getExtensionId().equals(EXTENSION_ID)) { + return null; + } + + var curationVid = CurationVID.parse(aVid.getExtensionPayload()); + if (curationVid == null) { + return null; + } + + var srcUser = curationVid.getUsername(); + + if (!documentService.existsAnnotationDocument(aDocument, srcUser)) { + log.error("Source CAS of [{}] for curation not found", srcUser); + return null; + } + + var vid = VID.parse(curationVid.getExtensionPayload()); + var cas = documentService.readAnnotationCas(aDocument, srcUser); + var fs = ICasUtil.selectAnnotationByAddr(cas, vid.getId()); + var ext = featureSupportRegistry.findExtension(aFeature).orElseThrow(); + return ext.getFeatureValue(aFeature, fs); + } + /** * Save annotation identified by aVID from user CAS to given curator's CAS */ diff --git a/inception/inception-ui-curation/src/main/java/de/tudarmstadt/ukp/inception/ui/curation/sidebar/config/CurationSidebarAutoConfiguration.java b/inception/inception-ui-curation/src/main/java/de/tudarmstadt/ukp/inception/ui/curation/sidebar/config/CurationSidebarAutoConfiguration.java index 93c458fbaad..442700741f9 100644 --- a/inception/inception-ui-curation/src/main/java/de/tudarmstadt/ukp/inception/ui/curation/sidebar/config/CurationSidebarAutoConfiguration.java +++ b/inception/inception-ui-curation/src/main/java/de/tudarmstadt/ukp/inception/ui/curation/sidebar/config/CurationSidebarAutoConfiguration.java @@ -32,6 +32,7 @@ import de.tudarmstadt.ukp.clarin.webanno.api.ProjectService; import de.tudarmstadt.ukp.clarin.webanno.security.UserDao; import de.tudarmstadt.ukp.inception.schema.AnnotationSchemaService; +import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupportRegistry; import de.tudarmstadt.ukp.inception.schema.layer.LayerSupportRegistry; import de.tudarmstadt.ukp.inception.ui.curation.sidebar.CurationEditorExtension; import de.tudarmstadt.ukp.inception.ui.curation.sidebar.CurationSidebarFactory; @@ -60,10 +61,12 @@ public CurationSidebarService curationSidebarService(EntityManager aEntityManage public CurationEditorExtension curationEditorExtension( AnnotationSchemaService aAnnotationService, DocumentService aDocumentService, ApplicationEventPublisher aApplicationEventPublisher, UserDao aUserRepository, - CurationSidebarService aCurationSidebarService) + CurationSidebarService aCurationSidebarService, + FeatureSupportRegistry aFeatureSupportRegistry) { return new CurationEditorExtension(aAnnotationService, aDocumentService, - aApplicationEventPublisher, aUserRepository, aCurationSidebarService); + aApplicationEventPublisher, aUserRepository, aCurationSidebarService, + aFeatureSupportRegistry); } @Bean("curationSidebar") diff --git a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureSupport.java b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureSupport.java index f0acc6d9eee..f2b8d450a07 100644 --- a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureSupport.java +++ b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/ConceptFeatureSupport.java @@ -26,7 +26,6 @@ import java.util.List; import java.util.Optional; -import org.apache.commons.lang3.StringUtils; import org.apache.uima.cas.CAS; import org.apache.uima.resource.metadata.TypeDescription; import org.apache.uima.resource.metadata.TypeSystemDescription; @@ -45,8 +44,6 @@ import de.tudarmstadt.ukp.inception.kb.graph.KBHandle; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState; import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.feature.FeatureEditor; import de.tudarmstadt.ukp.inception.schema.feature.FeatureSupport; @@ -263,31 +260,21 @@ public void generateFeature(TypeSystemDescription aTSD, TypeDescription aTD, } @Override - public List getLazyDetails(AnnotationFeature aFeature, String aLabel) + public List lookupLazyDetails(AnnotationFeature aFeature, Object aValue) { - if (StringUtils.isEmpty(aLabel)) { - return Collections.emptyList(); - } - - return asList(new VLazyDetailQuery(aFeature.getName(), aLabel)); - } - - @Override - public List renderLazyDetails(CAS aCas, AnnotationFeature aFeature, - VID aParamId, String aQuery) - { - List result = new ArrayList<>(); - - ConceptFeatureTraits traits = readTraits(aFeature); - KBHandle handle = getConceptHandle(aFeature, aQuery, traits); + if (aValue instanceof KBHandle) { + var handle = (KBHandle) aValue; + var result = new ArrayList(); + result.add(new VLazyDetailResult("Label", handle.getUiLabel())); - result.add(new VLazyDetailResult("Label", handle.getUiLabel())); + if (isNotBlank(handle.getDescription())) { + result.add(new VLazyDetailResult("Description", handle.getDescription())); + } - if (isNotBlank(handle.getDescription())) { - result.add(new VLazyDetailResult("Description", handle.getDescription())); + return result; } - return result; + return Collections.emptyList(); } @Override diff --git a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/MultiValueConceptFeatureSupport.java b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/MultiValueConceptFeatureSupport.java index bbf9de59f8f..18eb3eff1aa 100644 --- a/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/MultiValueConceptFeatureSupport.java +++ b/inception/inception-ui-kb/src/main/java/de/tudarmstadt/ukp/inception/ui/kb/feature/MultiValueConceptFeatureSupport.java @@ -26,10 +26,8 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; -import org.apache.commons.lang3.StringUtils; import org.apache.uima.cas.CAS; import org.apache.uima.cas.Feature; import org.apache.uima.cas.FeatureStructure; @@ -53,8 +51,6 @@ import de.tudarmstadt.ukp.inception.kb.graph.KBHandle; import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState; import de.tudarmstadt.ukp.inception.rendering.editorstate.FeatureState; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VID; -import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailQuery; import de.tudarmstadt.ukp.inception.rendering.vmodel.VLazyDetailResult; import de.tudarmstadt.ukp.inception.schema.adapter.IllegalFeatureValueException; import de.tudarmstadt.ukp.inception.schema.feature.FeatureEditor; @@ -245,7 +241,8 @@ public Serializable wrapFeatureValue(AnnotationFeature aFeature, CAS aCAS, Objec } if (aValue instanceof List) { - ArrayList wrapped = new ArrayList<>(); + var traits = readTraits(aFeature); + var wrapped = new ArrayList(); for (Object item : (List) aValue) { if (item instanceof KBHandle) { @@ -254,10 +251,9 @@ public Serializable wrapFeatureValue(AnnotationFeature aFeature, CAS aCAS, Objec } if (item instanceof String) { - String identifier = (String) item; - MultiValueConceptFeatureTraits traits = readTraits(aFeature); - KBHandle chbk = labelCache.get(aFeature, traits.getRepositoryId(), identifier); - KBHandle clone = new KBHandle(chbk.getIdentifier(), chbk.getUiLabel(), + var identifier = (String) item; + var chbk = labelCache.get(aFeature, traits.getRepositoryId(), identifier); + var clone = new KBHandle(chbk.getIdentifier(), chbk.getUiLabel(), chbk.getDescription(), chbk.getLanguage()); clone.setKB(chbk.getKB()); wrapped.add(clone); @@ -333,47 +329,22 @@ public String renderFeatureValue(AnnotationFeature aFeature, FeatureStructure aF } @Override - public List getLazyDetails(AnnotationFeature aFeature, FeatureStructure aFs) + public List lookupLazyDetails(AnnotationFeature aFeature, Object aValue) { - Feature labelFeature = aFs.getType().getFeatureByBaseName(aFeature.getName()); - - if (labelFeature == null) { - return Collections.emptyList(); - } - - List handles = getFeatureValue(aFeature, aFs); - if (handles == null) { - return Collections.emptyList(); - } - - return handles.stream() // - .flatMap(h -> getLazyDetails(aFeature, h.getIdentifier()).stream()) // - .collect(toList()); - } - - @Override - public List getLazyDetails(AnnotationFeature aFeature, String aIdentifier) - { - if (StringUtils.isEmpty(aIdentifier)) { - return Collections.emptyList(); - } - - return asList(new VLazyDetailQuery(aFeature.getName(), aIdentifier)); - } - - @Override - public List renderLazyDetails(CAS aCas, AnnotationFeature aFeature, - VID aParamId, String aQuery) - { - List result = new ArrayList<>(); - - MultiValueConceptFeatureTraits traits = readTraits(aFeature); - KBHandle handle = labelCache.get(aFeature, traits.getRepositoryId(), aQuery); - - result.add(new VLazyDetailResult("Label", handle.getUiLabel())); - - if (isNotBlank(handle.getDescription())) { - result.add(new VLazyDetailResult("Description", handle.getDescription())); + var result = new ArrayList(); + + if (aValue instanceof Iterable) { + var handles = (Iterable) aValue; + for (var h : handles) { + if (h instanceof KBHandle) { + var handle = (KBHandle) h; + result.add(new VLazyDetailResult("Label", handle.getUiLabel())); + + if (isNotBlank(handle.getDescription())) { + result.add(new VLazyDetailResult("Description", handle.getDescription())); + } + } + } } return result;