Skip to content

Commit

Permalink
#4205 - Ability to refresh document to load pending suggestions
Browse files Browse the repository at this point in the history
- Add a action bar button to refresh the document in case there are recommenders
- Wiggle the button a bit if there are pending suggestions
  • Loading branch information
reckart committed Sep 24, 2023
1 parent b826602 commit 4dd2a66
Show file tree
Hide file tree
Showing 9 changed files with 273 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import de.tudarmstadt.ukp.inception.editor.AnnotationEditorExtension;
import de.tudarmstadt.ukp.inception.editor.AnnotationEditorExtensionImplBase;
import de.tudarmstadt.ukp.inception.editor.action.AnnotationActionHandler;
import de.tudarmstadt.ukp.inception.recommendation.actionbar.RecommenderActionBarPanel;
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;
Expand Down Expand Up @@ -325,6 +326,9 @@ public void renderRequested(AjaxRequestTarget aTarget, AnnotatorState aState)
// also update their state to remain in sync with the new predictions
applicationEventPublisher
.publishEvent(new PredictionsSwitchedEvent(this, sessionOwner, aState));

aTarget.appendJavaScript("document.body.classList.remove('"
+ RecommenderActionBarPanel.STATE_PREDICTIONS_AVAILABLE + "')");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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.actionbar;

import org.apache.wicket.markup.html.panel.Panel;
import org.springframework.core.annotation.Order;

import de.tudarmstadt.ukp.clarin.webanno.api.annotation.actionbar.ActionBarExtension;
import de.tudarmstadt.ukp.clarin.webanno.api.annotation.page.AnnotationPageBase;
import de.tudarmstadt.ukp.clarin.webanno.ui.annotation.AnnotationPage;
import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService;
import de.tudarmstadt.ukp.inception.recommendation.config.RecommenderServiceAutoConfiguration;
import de.tudarmstadt.ukp.inception.rendering.editorstate.AnnotatorState;

/**
* <p>
* This class is exposed as a Spring Component via
* {@link RecommenderServiceAutoConfiguration#recommenderActionBarExtension}.
* </p>
*/
@Order(2000)
public class RecommenderActionBarExtension
implements ActionBarExtension
{
private final RecommendationService recommendationService;

public RecommenderActionBarExtension(RecommendationService aRecommendationService)
{
recommendationService = aRecommendationService;
}

@Override
public boolean accepts(AnnotationPageBase aPage)
{
if (!(aPage instanceof AnnotationPage)) {
return false;
}

return aPage.getModel() //
.map(AnnotatorState::getProject) //
.map(recommendationService::existsEnabledRecommender) //
.orElse(false).getObject();
}

@Override
public Panel createActionBarItem(String aId, AnnotationPageBase aPage)
{
return new RecommenderActionBarPanel(aId, aPage);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<!DOCTYPE html>
<!--
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.
-->
<html xmlns:wicket="http://wicket.apache.org">
<wicket:head>
<style>
.state-predictions-available .btn-refresh-document>* {
animation: btn-refresh-document-attention 6s linear infinite;
}

@keyframes btn-refresh-document-attention {
0%, 15%, 100% {
transform: rotate(0deg);
}

5% {
transform: rotate(-20deg);
animation-timing-function: ease-in;
}

10% {
transform: rotate(20deg);
animation-timing-function: ease-in;
}
}
</style>
</wicket:head>
<wicket:panel>
<div class="action-bar-group">
<div class="btn-group">
<button wicket:id="refreshDocument" class="btn btn-action-bar btn-refresh-document" type="button"
wicket:message="title:refreshDocument">
<i class="fas fa-sync"></i>
</button>
</div>
</div>
</wicket:panel>

</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* 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.actionbar;

import java.lang.invoke.MethodHandles;

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.panel.Panel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.tudarmstadt.ukp.clarin.webanno.api.annotation.page.AnnotationPageBase;
import de.tudarmstadt.ukp.clarin.webanno.support.lambda.LambdaAjaxLink;

public class RecommenderActionBarPanel
extends Panel
{
private static final long serialVersionUID = -2999081548651637508L;

private static final Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

public static final String STATE_PREDICTIONS_AVAILABLE = "state-predictions-available";

private final LambdaAjaxLink refreshDocumentButton;

private final AnnotationPageBase page;

public RecommenderActionBarPanel(String aId, AnnotationPageBase aPage)
{
super(aId);

page = aPage;

refreshDocumentButton = new LambdaAjaxLink("refreshDocument", this::actionRefreshDocument);
add(refreshDocumentButton);
}

private void actionRefreshDocument(AjaxRequestTarget aTarget)
{
page.actionRefreshDocument(aTarget);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 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.

refreshDocument=Refresh document
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import de.tudarmstadt.ukp.clarin.webanno.security.UserDao;
import de.tudarmstadt.ukp.inception.preferences.PreferencesService;
import de.tudarmstadt.ukp.inception.recommendation.RecommendationEditorExtension;
import de.tudarmstadt.ukp.inception.recommendation.actionbar.RecommenderActionBarExtension;
import de.tudarmstadt.ukp.inception.recommendation.api.LearningRecordService;
import de.tudarmstadt.ukp.inception.recommendation.api.RecommendationService;
import de.tudarmstadt.ukp.inception.recommendation.api.RecommenderFactoryRegistry;
Expand Down Expand Up @@ -219,4 +220,11 @@ public RecommendationRelationRenderer recommendationRelationRenderer(
return new RecommendationRelationRenderer(aRecommendationService, aAnnotationService,
aFsRegistry);
}

@Bean
public RecommenderActionBarExtension recommenderActionBarExtension(
RecommendationService aRecommendationService)
{
return new RecommenderActionBarExtension(aRecommendationService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,12 @@
*/
package de.tudarmstadt.ukp.inception.recommendation.footer;

import static java.util.Collections.emptySet;
import static java.util.stream.Collectors.toSet;

import java.io.Serializable;
import java.util.Collection;
import java.util.Set;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
Expand All @@ -35,22 +40,50 @@ public class RRecommenderLogMessage

private static final String MESSAGE = "message";
private static final String LEVEL = "level";
private static final String ADD_MARKER_CLASSES = "addClasses";
private static final String REMOVE_MARKER_CLASSES = "removeClasses";

private final LogLevel level;
private final String message;
private final Set<String> markerClassesToRemove;
private final Set<String> markerClassesToAdd;

public RRecommenderLogMessage(LogMessage aMessage)
{
level = aMessage.getLevel();
message = aMessage.getMessage();
markerClassesToAdd = emptySet();
markerClassesToRemove = emptySet();
}

@JsonCreator
public RRecommenderLogMessage(@JsonProperty(LEVEL) LogLevel aLevel,
@JsonProperty(MESSAGE) String aMessage)
{
this(aLevel, aMessage, null, null);
}

@JsonCreator
public RRecommenderLogMessage(@JsonProperty(LEVEL) LogLevel aLevel,
@JsonProperty(MESSAGE) String aMessage,
@JsonProperty(value = ADD_MARKER_CLASSES) Collection<String> aMarkerClassesToAdd,
@JsonProperty(value = REMOVE_MARKER_CLASSES) Collection<String> aMarkerClassesToRemove)
{
level = aLevel;
message = aMessage;

if (aMarkerClassesToAdd == null) {
markerClassesToAdd = emptySet();
}
else {
markerClassesToAdd = aMarkerClassesToAdd.stream().collect(toSet());
}

if (aMarkerClassesToRemove == null) {
markerClassesToRemove = emptySet();
}
else {
markerClassesToRemove = aMarkerClassesToRemove.stream().collect(toSet());
}
}

@JsonProperty(LEVEL)
Expand All @@ -65,11 +98,22 @@ public String getMessage()
return message;
}

@JsonProperty(ADD_MARKER_CLASSES)
public Set<String> getMarkerClassesToAdd()
{
return markerClassesToAdd;
}

@JsonProperty(REMOVE_MARKER_CLASSES)
public Set<String> getMarkerClassesToRemove()
{
return markerClassesToRemove;
}

@Override
public String toString()
{
return new ToStringBuilder(this, ToStringStyle.JSON_STYLE).append(LEVEL, level)
.append(MESSAGE, message).toString();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import static de.tudarmstadt.ukp.inception.websocket.config.WebSocketConstants.TOPIC_ELEMENT_PROJECT;
import static de.tudarmstadt.ukp.inception.websocket.config.WebSocketConstants.TOPIC_ELEMENT_USER;
import static de.tudarmstadt.ukp.inception.websocket.config.WebSocketConstants.TOPIC_RECOMMENDER;
import static java.util.Arrays.asList;
import static java.util.Collections.emptyList;

import java.lang.invoke.MethodHandles;

Expand All @@ -35,7 +37,9 @@
import org.springframework.stereotype.Controller;

import de.tudarmstadt.ukp.clarin.webanno.model.Project;
import de.tudarmstadt.ukp.inception.recommendation.actionbar.RecommenderActionBarPanel;
import de.tudarmstadt.ukp.inception.recommendation.event.RecommenderTaskNotificationEvent;
import de.tudarmstadt.ukp.inception.recommendation.tasks.PredictionTask;

@ConditionalOnWebApplication
@ConditionalOnExpression("${websocket.enabled:true} and ${websocket.recommender-events.enabled:true}")
Expand All @@ -57,8 +61,18 @@ public RecommendationEventWebsocketControllerImpl(@Autowired SimpMessagingTempla
public void onRecommenderTaskEvent(RecommenderTaskNotificationEvent aEvent)
{
Project project = aEvent.getProject();
RRecommenderLogMessage eventMsg = new RRecommenderLogMessage(aEvent.getMessage().getLevel(),
aEvent.getMessage().getMessage());
RRecommenderLogMessage eventMsg;
if (aEvent.getSource() instanceof PredictionTask) {
eventMsg = new RRecommenderLogMessage(aEvent.getMessage().getLevel(),
aEvent.getMessage().getMessage(),
asList(RecommenderActionBarPanel.STATE_PREDICTIONS_AVAILABLE), emptyList());

}
else {
eventMsg = new RRecommenderLogMessage(aEvent.getMessage().getLevel(),
aEvent.getMessage().getMessage());
}

String channel = getChannel(project, aEvent.getUser());

LOG.debug("Sending event to [{}]: {}", channel, eventMsg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
interface RRecommenderLogMessage {
level: "INFO" | "WARN" | "ERROR"
message: string
addClasses: string[]
removeClasses: string[]
}
export let wsEndpointUrl: string; // should this be full ws://... url
Expand Down Expand Up @@ -72,14 +74,15 @@
}
var msgBody = JSON.parse(msg.body) as RRecommenderLogMessage;
console.log(msgBody)
msgBody.removeClasses?.forEach(c => document.body.classList.remove(c))
msgBody.addClasses?.forEach(c => document.body.classList.add(c))
switch (msgBody.level) {
case "ERROR":
feedbackPanelExtension.addErrorToFeedbackPanel(msgBody.message);
break;
case "WARN":
feedbackPanelExtension.addEWarningToFeedbackPanel(
msgBody.message
);
feedbackPanelExtension.addEWarningToFeedbackPanel(msgBody.message);
break;
case "INFO":
feedbackPanelExtension.addInfoToFeedbackPanel(msgBody.message);
Expand Down

0 comments on commit 4dd2a66

Please sign in to comment.