diff --git a/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/AssistantSidebar.java b/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/AssistantSidebar.java
index 846ebe1db58..927e0b13123 100644
--- a/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/AssistantSidebar.java
+++ b/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/AssistantSidebar.java
@@ -17,17 +17,34 @@
*/
package de.tudarmstadt.ukp.inception.assistant.sidebar;
+import static de.tudarmstadt.ukp.inception.assistant.sidebar.AssistantSidebarPrefs.KEY_ASSISTANT_SIDEBAR_PREFS;
+import static de.tudarmstadt.ukp.inception.support.lambda.HtmlElementEvents.CHANGE_EVENT;
+
import org.apache.wicket.ajax.AjaxRequestTarget;
+import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.IModel;
+import org.apache.wicket.model.Model;
import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.wicketstuff.event.annotation.OnEvent;
+import de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome6IconType;
import de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasProvider;
import de.tudarmstadt.ukp.clarin.webanno.security.UserDao;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPageBase2;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.sidebar.AnnotationSidebar_ImplBase;
+import de.tudarmstadt.ukp.inception.annotation.events.FeatureValueUpdatedEvent;
import de.tudarmstadt.ukp.inception.assistant.AssistantService;
import de.tudarmstadt.ukp.inception.assistant.documents.DocumentQueryService;
+import de.tudarmstadt.ukp.inception.bootstrap.IconToggleBox;
import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler;
+import de.tudarmstadt.ukp.inception.preferences.PreferencesService;
+import de.tudarmstadt.ukp.inception.rendering.vmodel.VID;
+import de.tudarmstadt.ukp.inception.scheduling.SchedulingService;
+import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxFormComponentUpdatingBehavior;
+import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxFormSubmittingBehavior;
import de.tudarmstadt.ukp.inception.support.lambda.LambdaAjaxLink;
+import de.tudarmstadt.ukp.inception.support.lambda.LambdaModelAdapter;
public class AssistantSidebar
extends AnnotationSidebar_ImplBase
@@ -37,31 +54,98 @@ public class AssistantSidebar
private @SpringBean UserDao userService;
private @SpringBean AssistantService assistantService;
private @SpringBean DocumentQueryService documentQueryService;
+ private @SpringBean SchedulingService schedulingService;
+ private @SpringBean PreferencesService preferencesService;
private AssistantPanel chat;
+ private CompoundPropertyModel
sidebarPrefs;
+ private IModel debugMode;
+
public AssistantSidebar(String aId, AnnotationActionHandler aActionHandler,
CasProvider aCasProvider, AnnotationPageBase2 aAnnotationPage)
{
super(aId, aActionHandler, aCasProvider, aAnnotationPage);
+ sidebarPrefs = new CompoundPropertyModel<>(Model.of(loadSidebarPrefs()));
+
+ debugMode = new LambdaModelAdapter<>( //
+ () -> assistantService.isDebugMode(userService.getCurrentUsername(),
+ getModelObject().getProject()), //
+ onOff -> assistantService.setDebugMode(userService.getCurrentUsername(),
+ getModelObject().getProject(), onOff));
+
chat = new AssistantPanel("chat");
queue(chat);
- queue(new LambdaAjaxLink("reindex", this::actionReindex));
+ var form = new Form<>("form", sidebarPrefs);
+ add(form);
+
+ form.add(new LambdaAjaxLink("reindex", this::actionReindex));
+
+ form.add(new LambdaAjaxLink("clear", this::actionClear));
+
+ form.add(new IconToggleBox("watchMode") //
+ .setCheckedIcon(FontAwesome6IconType.eye_s) //
+ .setCheckedTitle(Model.of("Watching annotation actions and commenting")) //
+ .setUncheckedIcon(FontAwesome6IconType.eye_slash_s) //
+ .setUncheckedTitle(Model.of("Not watching annotation actions")) //
+ .add(new LambdaAjaxFormSubmittingBehavior(CHANGE_EVENT,
+ _target -> saveSidebarPrefs())));
+
+ form.add(new IconToggleBox("debugMode") //
+ .setCheckedIcon(FontAwesome6IconType.bug_s) //
+ .setCheckedTitle(Model.of("Recording and showing internal messages")) //
+ .setUncheckedIcon(FontAwesome6IconType.bug_slash_s) //
+ .setUncheckedTitle(Model.of("Not recoording and showing internal messages")) //
+ .setModel(debugMode) //
+ .add(new LambdaAjaxFormComponentUpdatingBehavior(CHANGE_EVENT,
+ _target -> _target.add(chat))));
+ }
+
+ private AssistantSidebarPrefs loadSidebarPrefs()
+ {
+ var sessionOwner = userService.getCurrentUser();
+ return preferencesService.loadTraitsForUserAndProject(KEY_ASSISTANT_SIDEBAR_PREFS,
+ sessionOwner, getModelObject().getProject());
+ }
- queue(new LambdaAjaxLink("clear", this::actionClear));
+ private void saveSidebarPrefs()
+ {
+ var sessionOwner = userService.getCurrentUser();
+ preferencesService.saveTraitsForUserAndProject(KEY_ASSISTANT_SIDEBAR_PREFS, sessionOwner,
+ getModelObject().getProject(), sidebarPrefs.getObject());
}
private void actionReindex(AjaxRequestTarget aTarget)
{
- documentQueryService.rebuildIndexAsync(getAnnotationPage().getProject());
+ documentQueryService.rebuildIndexAsync(getModelObject().getProject());
}
private void actionClear(AjaxRequestTarget aTarget)
{
var sessionOwner = userService.getCurrentUsername();
- var project = getAnnotationPage().getProject();
+ var project = getModelObject().getProject();
assistantService.clearConversation(sessionOwner, project);
}
+
+ @OnEvent
+ public void onFeatureValueUpdated(FeatureValueUpdatedEvent aEvent)
+ {
+ if (!sidebarPrefs.map(AssistantSidebarPrefs::isWatchMode).orElse(false).getObject()
+ && aEvent.getNewValue() == null) {
+ return;
+ }
+
+ var sessionOwner = userService.getCurrentUser();
+
+ schedulingService.enqueue(WatchAnnotationTask.builder() //
+ .withTrigger("Assistant watching") //
+ .withSessionOwner(sessionOwner) //
+ .withProject(aEvent.getProject()) //
+ .withDocument(aEvent.getDocument()) //
+ .withDataOwner(aEvent.getDocumentOwner()) //
+ .withAnnotation(VID.of(aEvent.getFS())) //
+ .build());
+ }
}
diff --git a/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/AssistantSidebarPrefs.java b/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/AssistantSidebarPrefs.java
new file mode 100644
index 00000000000..e66b63f13fc
--- /dev/null
+++ b/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/AssistantSidebarPrefs.java
@@ -0,0 +1,45 @@
+/*
+ * 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.assistant.sidebar;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import de.tudarmstadt.ukp.inception.preferences.PreferenceKey;
+import de.tudarmstadt.ukp.inception.preferences.PreferenceValue;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AssistantSidebarPrefs
+ implements PreferenceValue
+{
+ private static final long serialVersionUID = -5879519353175794875L;
+
+ public static final PreferenceKey KEY_ASSISTANT_SIDEBAR_PREFS = //
+ new PreferenceKey<>(AssistantSidebarPrefs.class, "annotation/editor/assistant-sidebar");
+
+ private boolean watchMode;
+
+ public boolean isWatchMode()
+ {
+ return watchMode;
+ }
+
+ public void setWatchMode(boolean aWatchMode)
+ {
+ watchMode = aWatchMode;
+ }
+}
diff --git a/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/WatchAnnotationTask.java b/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/WatchAnnotationTask.java
new file mode 100644
index 00000000000..f2b0562dd39
--- /dev/null
+++ b/inception/inception-assistant/src/main/java/de/tudarmstadt/ukp/inception/assistant/sidebar/WatchAnnotationTask.java
@@ -0,0 +1,218 @@
+/*
+ * 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.assistant.sidebar;
+
+import static de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasAccessMode.SHARED_READ_ONLY_ACCESS;
+import static de.tudarmstadt.ukp.clarin.webanno.api.casstorage.CasUpgradeMode.AUTO_CAS_UPGRADE;
+import static de.tudarmstadt.ukp.inception.assistant.model.MChatRoles.SYSTEM;
+import static de.tudarmstadt.ukp.inception.scheduling.MatchResult.NO_MATCH;
+import static de.tudarmstadt.ukp.inception.scheduling.MatchResult.QUEUE_THIS;
+import static de.tudarmstadt.ukp.inception.support.json.JSONUtil.toPrettyJsonString;
+import static de.tudarmstadt.ukp.inception.support.uima.ICasUtil.selectAnnotationByAddr;
+import static java.lang.String.join;
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.lang3.StringUtils.normalizeSpace;
+
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+
+import org.apache.commons.lang3.Validate;
+import org.apache.uima.jcas.tcas.Annotation;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import de.tudarmstadt.ukp.clarin.webanno.api.casstorage.session.CasStorageSession;
+import de.tudarmstadt.ukp.clarin.webanno.model.SourceDocument;
+import de.tudarmstadt.ukp.dkpro.core.api.segmentation.type.Sentence;
+import de.tudarmstadt.ukp.inception.assistant.AssistantService;
+import de.tudarmstadt.ukp.inception.assistant.model.MTextMessage;
+import de.tudarmstadt.ukp.inception.documents.api.DocumentService;
+import de.tudarmstadt.ukp.inception.rendering.vmodel.VID;
+import de.tudarmstadt.ukp.inception.scheduling.MatchResult;
+import de.tudarmstadt.ukp.inception.scheduling.MatchableTask;
+import de.tudarmstadt.ukp.inception.scheduling.Task;
+import de.tudarmstadt.ukp.inception.schema.api.AnnotationSchemaService;
+
+public class WatchAnnotationTask
+ extends Task
+ implements MatchableTask
+{
+ public static final String TYPE = "WatchAnnotationTask";
+ private static final String ACTOR = "Annotation watcher";
+
+ private @Autowired AnnotationSchemaService schemaService;
+ private @Autowired AssistantService assistantService;
+ private @Autowired DocumentService documentService;
+
+ private final SourceDocument document;
+ private final String dataOwner;
+ private final VID annotation;
+
+ public WatchAnnotationTask(Builder extends Builder>> aBuilder)
+ {
+ super(aBuilder.withType(TYPE));
+
+ requireNonNull(getUser().orElse(null), "Session owner must be set");
+
+ document = aBuilder.document;
+ dataOwner = aBuilder.dataOwner;
+ annotation = aBuilder.annotation;
+ }
+
+ @Override
+ public MatchResult matches(Task aTask)
+ {
+ if (aTask instanceof WatchAnnotationTask) {
+ if (Objects.equals(getProject().getId(), aTask.getProject().getId())
+ && Objects.equals(getUser().get(), aTask.getUser().orElse(null))) {
+ return QUEUE_THIS;
+ }
+ }
+
+ return NO_MATCH;
+ }
+
+ @Override
+ public void execute() throws Exception
+ {
+ try (var session = CasStorageSession.open()) {
+ var cas = documentService.readAnnotationCas(document, dataOwner, AUTO_CAS_UPGRADE,
+ SHARED_READ_ONLY_ACCESS);
+
+ var ann = selectAnnotationByAddr(cas, annotation.getId());
+ if (ann == null) {
+ return;
+ }
+
+ var contextSentence = cas.select(Sentence.class).covering(ann).nullOK().get();
+ if (contextSentence == null) {
+ return;
+ }
+
+ var instance = annotationToJson(ann, contextSentence);
+
+ var checkQuestion = MTextMessage.builder() //
+ .withActor(ACTOR) //
+ .withRole(SYSTEM).internal().ephemeral() //
+ .withMessage(join("\n", //
+ "Is the following annotation correct or not. Answer true or false.", //
+ "\n", //
+ "```json", //
+ instance, //
+ "```")) //
+ .build();
+
+ var checkResult = assistantService.processInternalCallSync(
+ getUser().get().getUsername(), getProject(), BooleanQuestion.class,
+ checkQuestion);
+
+ if (checkResult.payload().answer()) {
+ return;
+ }
+
+ var inquiryContext = MTextMessage.builder() //
+ .withActor(ACTOR) //
+ .withRole(SYSTEM).internal().ephemeral() //
+ .withMessage(join("\n", //
+ "Your task is to advise the user about potential problems with the following annotation.", //
+ "Give one response per annotation.", //
+ "If expanding or reducing the span seems appropriate, mention that.", //
+ "Use markdown for formatting.", //
+ "", //
+ "```json", //
+ instance, //
+ "```")) //
+ .build();
+
+ assistantService.processAgentMessage(getUser().get().getUsername(), getProject(),
+ inquiryContext);
+ }
+ }
+
+ private String annotationToJson(Annotation aAnnotation, Annotation aContext) throws IOException
+ {
+ var instance = new LinkedHashMap();
+
+ instance.put("span", normalizeSpace(aAnnotation.getCoveredText()));
+
+ var docText = aAnnotation.getCAS().getDocumentText();
+ var context = docText.substring(aContext.getBegin(), aAnnotation.getBegin()) //
+ + " " //
+ + aAnnotation.getCoveredText() //
+ + " " //
+ + docText.substring(aAnnotation.getEnd(), aContext.getEnd());
+ instance.put("context", normalizeSpace(context));
+
+ var adapter = schemaService.findAdapter(getProject(), aAnnotation);
+ var attributes = new LinkedHashMap();
+ for (var feature : adapter.listFeatures()) {
+ attributes.put(normalizeSpace(feature.getUiName()),
+ normalizeSpace(adapter.getFeatureValue(feature, aAnnotation)));
+ }
+ instance.put("annotation", attributes);
+
+ return toPrettyJsonString(instance);
+ }
+
+ private static record BooleanQuestion(boolean answer) {};
+
+ public static Builder> builder()
+ {
+ return new Builder<>();
+ }
+
+ public static class Builder>
+ extends Task.Builder
+ {
+ private SourceDocument document;
+ private String dataOwner;
+ private VID annotation;
+
+ protected Builder()
+ {
+ }
+
+ @SuppressWarnings("unchecked")
+ public T withAnnotation(VID aVid)
+ {
+ annotation = aVid;
+ return (T) this;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T withDocument(SourceDocument aDocument)
+ {
+ document = aDocument;
+ return (T) this;
+ }
+
+ @SuppressWarnings("unchecked")
+ public T withDataOwner(String aDataOwner)
+ {
+ dataOwner = aDataOwner;
+ return (T) this;
+ }
+
+ public WatchAnnotationTask build()
+ {
+ Validate.notNull(project, "Parameter [project] must be specified");
+
+ return new WatchAnnotationTask(this);
+ }
+ }
+}
diff --git a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/recommendation/MetadataSuggestionSupport.java b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/recommendation/MetadataSuggestionSupport.java
index 17f0ff3d9eb..7165656b014 100644
--- a/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/recommendation/MetadataSuggestionSupport.java
+++ b/inception/inception-layer-docmetadata/src/main/java/de/tudarmstadt/ukp/inception/ui/core/docanno/recommendation/MetadataSuggestionSupport.java
@@ -226,9 +226,9 @@ private void hideSpanSuggestionsThatMatchAnnotations(boolean singleton,
sugGroup.hideAll(FLAG_OVERLAP);
}
else {
- for (var sug : sugGroup) {
- if (label.equals(sug.getLabel())) {
- sug.hide(FLAG_OVERLAP);
+ for (var suggestion : sugGroup) {
+ if (label.equals(suggestion.getLabel())) {
+ suggestion.hide(FLAG_OVERLAP);
}
}
}
diff --git a/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/recommender/TrainingInstance.java b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/recommender/TrainingInstance.java
new file mode 100644
index 00000000000..559f05489a8
--- /dev/null
+++ b/inception/inception-recommendation-api/src/main/java/de/tudarmstadt/ukp/inception/recommendation/api/recommender/TrainingInstance.java
@@ -0,0 +1,23 @@
+/*
+ * 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.recommendation.api.recommender;
+
+public interface TrainingInstance
+{
+
+}
diff --git a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/sidebar/llm/InteractiveRecommenderSidebar.java b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/sidebar/llm/InteractiveRecommenderSidebar.java
index 9bc58109d97..d495456021c 100644
--- a/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/sidebar/llm/InteractiveRecommenderSidebar.java
+++ b/inception/inception-recommendation/src/main/java/de/tudarmstadt/ukp/inception/recommendation/sidebar/llm/InteractiveRecommenderSidebar.java
@@ -383,7 +383,7 @@ private List listLayers(Recommender aRecommender)
private void execute(AjaxRequestTarget aTarget, Form aForm) throws Exception
{
var sessionOwner = userService.getCurrentUser();
- var state = getAnnotationPage().getModelObject();
+ var state = getModelObject();
var document = state.getDocument();
var dataOwner = state.getUser().getUsername();
var rec = aForm.getModelObject();
diff --git a/inception/inception-scheduling/src/main/java/de/tudarmstadt/ukp/inception/scheduling/MatchResult.java b/inception/inception-scheduling/src/main/java/de/tudarmstadt/ukp/inception/scheduling/MatchResult.java
index 6e5f8dafbdf..569f7449f1c 100644
--- a/inception/inception-scheduling/src/main/java/de/tudarmstadt/ukp/inception/scheduling/MatchResult.java
+++ b/inception/inception-scheduling/src/main/java/de/tudarmstadt/ukp/inception/scheduling/MatchResult.java
@@ -34,5 +34,11 @@ public enum MatchResult
* Discard the incoming task if it matches an already enqueued task. If a matching task is
* already scheduled or running, then queue the incoming task.
*/
- DISCARD_OR_QUEUE_THIS;
+ DISCARD_OR_QUEUE_THIS,
+
+ /**
+ * Queue this task. It will be run immediately or after other matching tasks have been run. It
+ * will not run parallel to matching tasks.
+ */
+ QUEUE_THIS;
}
diff --git a/inception/inception-scheduling/src/main/java/de/tudarmstadt/ukp/inception/scheduling/SchedulingServiceImpl.java b/inception/inception-scheduling/src/main/java/de/tudarmstadt/ukp/inception/scheduling/SchedulingServiceImpl.java
index 558e86fbf00..11f7199f1f2 100644
--- a/inception/inception-scheduling/src/main/java/de/tudarmstadt/ukp/inception/scheduling/SchedulingServiceImpl.java
+++ b/inception/inception-scheduling/src/main/java/de/tudarmstadt/ukp/inception/scheduling/SchedulingServiceImpl.java
@@ -247,6 +247,10 @@ public synchronized void enqueue(Task aTask)
// the incoming task supersedes them).
tasksToUnqueue.add(enqueuedTask);
break;
+ case QUEUE_THIS:
+ // Queue this task to be run potentially after other matching tasks have been
+ // completed
+ break;
case NO_MATCH:
// Ignore
break;
diff --git a/inception/inception-sharing/src/main/java/de/tudarmstadt/ukp/inception/sharing/project/InviteProjectSettingsPanel.java b/inception/inception-sharing/src/main/java/de/tudarmstadt/ukp/inception/sharing/project/InviteProjectSettingsPanel.java
index df00cd214f4..7b28421734e 100644
--- a/inception/inception-sharing/src/main/java/de/tudarmstadt/ukp/inception/sharing/project/InviteProjectSettingsPanel.java
+++ b/inception/inception-sharing/src/main/java/de/tudarmstadt/ukp/inception/sharing/project/InviteProjectSettingsPanel.java
@@ -17,6 +17,7 @@
*/
package de.tudarmstadt.ukp.inception.sharing.project;
+import static de.tudarmstadt.ukp.inception.support.lambda.HtmlElementEvents.CHANGE_EVENT;
import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.visibleWhen;
import static de.tudarmstadt.ukp.inception.support.lambda.LambdaBehavior.visibleWhenNot;
import static java.util.Arrays.asList;
@@ -103,14 +104,14 @@ protected void onDisabled(ComponentTag tag)
detailsForm.add(new CheckBox("guestAccessible").setOutputMarkupId(true)
.add(visibleWhen(() -> inviteServiceProperties.isGuestsEnabled()))
- .add(new LambdaAjaxFormSubmittingBehavior("change", _t -> _t.add(this))));
+ .add(new LambdaAjaxFormSubmittingBehavior(CHANGE_EVENT, _t -> _t.add(this))));
DropDownChoice askForEMail = new DropDownChoice<>("askForEMail",
asList(Mandatoriness.values()), new EnumChoiceRenderer<>(this));
askForEMail.setOutputMarkupId(true);
askForEMail.add(visibleWhen(() -> inviteServiceProperties.isGuestsEnabled()
&& invite.map(ProjectInvite::isGuestAccessible).orElse(false).getObject()));
- askForEMail.add(new LambdaAjaxFormSubmittingBehavior("change", _t -> _t.add(this)));
+ askForEMail.add(new LambdaAjaxFormSubmittingBehavior(CHANGE_EVENT, _t -> _t.add(this)));
detailsForm.add(askForEMail);
detailsForm.add(new TextField<>("userIdPlaceholder")
diff --git a/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/json/JSONUtil.java b/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/json/JSONUtil.java
index 89537a7cf60..ea6b4bf1ea0 100644
--- a/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/json/JSONUtil.java
+++ b/inception/inception-support/src/main/java/de/tudarmstadt/ukp/inception/support/json/JSONUtil.java
@@ -93,12 +93,14 @@ public static String toJsonString(Object aObject) throws IOException
public static String toJsonString(ObjectMapper aMapper, boolean aPretty, Object aObject)
throws IOException
{
- StringWriter out = new StringWriter();
+ var out = new StringWriter();
+
+ var jsonGenerator = aMapper.getFactory().createGenerator(out);
- JsonGenerator jsonGenerator = aMapper.getFactory().createGenerator(out);
if (aPretty) {
- jsonGenerator.setPrettyPrinter(new DefaultPrettyPrinter()
- .withObjectIndenter(new DefaultIndenter().withLinefeed("\n")));
+ jsonGenerator.setPrettyPrinter(new DefaultPrettyPrinter() //
+ .withObjectIndenter(new DefaultIndenter() //
+ .withLinefeed("\n")));
}
jsonGenerator.writeObject(aObject);
@@ -110,9 +112,8 @@ public static T fromJsonString(Class aClass, String aJSON) throws IOExcep
if (aJSON == null) {
return null;
}
- else {
- return getObjectMapper().readValue(aJSON, aClass);
- }
+
+ return getObjectMapper().readValue(aJSON, aClass);
}
public static T fromValidatedJsonString(Class aClass, String aJSON, JsonSchema aSchema)