diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java index dbd9bd0e..110bf6fa 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/action/ActionDefinition.java @@ -775,6 +775,12 @@ public enum ActionDefinition { ImageIcon.SEND_QUIT, PageStateDefinitionImpl.MONITORING_CLIENT_CONNECTION, ActionCategory.FORM), + MONITOR_EXAM_CLIENT_CONNECTION_LOCK( + new LocTextKey("sebserver.monitoring.exam.connection.action.instruction.lock"), + ImageIcon.LOCK, + PageStateDefinitionImpl.MONITORING_CLIENT_CONNECTION, + ActionCategory.FORM), + MONITOR_EXAM_CLIENT_CONNECTION_PROCTORING( new LocTextKey("sebserver.monitoring.exam.connection.action.proctoring"), ImageIcon.PROCTOR_SINGLE, diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java index 13c4bbcb..b0ab27d3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java @@ -8,7 +8,9 @@ package ch.ethz.seb.sebserver.gui.content.monitoring; +import java.util.Arrays; import java.util.Collection; +import java.util.HashSet; import java.util.function.BooleanSupplier; import java.util.function.Supplier; @@ -119,6 +121,7 @@ public class MonitoringClientConnection implements TemplateComposer { private final I18nSupport i18nSupport; private final InstructionProcessor instructionProcessor; private final SEBClientEventDetailsPopup sebClientLogDetailsPopup; + private final SEBSendLockPopup sebSendLockPopup; private final MonitoringProctoringService monitoringProctoringService; private final long pollInterval; private final int pageSize; @@ -133,6 +136,7 @@ public class MonitoringClientConnection implements TemplateComposer { final InstructionProcessor instructionProcessor, final SEBClientEventDetailsPopup sebClientLogDetailsPopup, final MonitoringProctoringService monitoringProctoringService, + final SEBSendLockPopup sebSendLockPopup, @Value("${sebserver.gui.webservice.poll-interval:500}") final long pollInterval, @Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) { @@ -144,6 +148,7 @@ public class MonitoringClientConnection implements TemplateComposer { this.monitoringProctoringService = monitoringProctoringService; this.pollInterval = pollInterval; this.sebClientLogDetailsPopup = sebClientLogDetailsPopup; + this.sebSendLockPopup = sebSendLockPopup; this.pageSize = pageSize; this.typeFilter = new TableFilterAttribute( @@ -371,6 +376,14 @@ public class MonitoringClientConnection implements TemplateComposer { return action; }) .noEventPropagation() + .publishIf(() -> isExamSupporter.getAsBoolean() && + connectionData.clientConnection.status.clientActiveStatus) + + .newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_LOCK) + .withEntityKey(parentEntityKey) + .withExec(action -> this.sebSendLockPopup.show(action, + some -> new HashSet<>(Arrays.asList(connectionToken)))) + .noEventPropagation() .publishIf(() -> isExamSupporter.getAsBoolean() && connectionData.clientConnection.status.clientActiveStatus); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/SEBSendLockPopup.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/SEBSendLockPopup.java index eae97062..ae3437d4 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/SEBSendLockPopup.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/SEBSendLockPopup.java @@ -76,44 +76,48 @@ public class SEBSendLockPopup { final PageAction action, final Function, Set> selectionFunction) { - final PageContext pageContext = action.pageContext(); - final Set selection = selectionFunction.apply(ClientConnection.getStatusPredicate( - ConnectionStatus.CONNECTION_REQUESTED, - ConnectionStatus.ACTIVE)); + try { - if (selection == null || selection.isEmpty()) { - action - .pageContext() - .publishInfo(new LocTextKey("sebserver.monitoring.lock.noselection")); - return action; + final PageContext pageContext = action.pageContext(); + final Set selection = selectionFunction.apply(ClientConnection.getStatusPredicate( + ConnectionStatus.CONNECTION_REQUESTED, + ConnectionStatus.ACTIVE)); + + if (selection == null || selection.isEmpty()) { + action + .pageContext() + .publishInfo(new LocTextKey("sebserver.monitoring.lock.noselection")); + return action; + } + + final String connectionTokens = StringUtils.join(selection, Constants.LIST_SEPARATOR_CHAR); + final boolean showList = selection.size() > 1; + final PopupComposer popupComposer = new PopupComposer( + this.pageService, + pageContext, + connectionTokens, + showList); + + final ModalInputDialog> dialog = + new ModalInputDialog>( + action.pageContext().getParent().getShell(), + this.pageService.getWidgetFactory()) + .setDialogWidth(800) + .setDialogHeight(showList ? 500 : 200); + + final Predicate> doLock = formHandle -> propagateLockInstruction( + connectionTokens, + pageContext, + formHandle); + + dialog.open( + TITLE_TEXT_KEY, + doLock, + Utils.EMPTY_EXECUTION, + popupComposer); + } catch (final Exception e) { + action.pageContext().notifyUnexpectedError(e); } - - final String connectionTokens = StringUtils.join(selection, Constants.LIST_SEPARATOR_CHAR); - final boolean showList = selection.size() > 1; - final PopupComposer popupComposer = new PopupComposer( - this.pageService, - pageContext, - connectionTokens, - showList); - - final ModalInputDialog> dialog = - new ModalInputDialog>( - action.pageContext().getParent().getShell(), - this.pageService.getWidgetFactory()) - .setDialogWidth(800) - .setDialogHeight(showList ? 500 : 200); - - final Predicate> doLock = formHandle -> propagateLockInstruction( - connectionTokens, - pageContext, - formHandle); - - dialog.open( - TITLE_TEXT_KEY, - doLock, - Utils.EMPTY_EXECUTION, - popupComposer); - return action; } @@ -195,17 +199,23 @@ public class SEBSendLockPopup { final PageContext pageContext, final FormHandle formHandle) { - final EntityKey examKey = pageContext.getEntityKey(); - final String lockMessage = formHandle - .getForm() - .getFieldValue(ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_FORCE_LOCK_SCREEN.MESSAGE); + try { - this.instructionProcessor.propagateSEBLockInstruction( - examKey.modelId, - lockMessage, - null, - connectionTokens, - pageContext); + final EntityKey examKey = pageContext.getEntityKey(); + final String lockMessage = formHandle + .getForm() + .getFieldValue(ClientInstruction.SEB_INSTRUCTION_ATTRIBUTES.SEB_FORCE_LOCK_SCREEN.MESSAGE); + + this.instructionProcessor.propagateSEBLockInstruction( + examKey.modelId, + lockMessage, + null, + connectionTokens, + pageContext); + + } catch (final Exception e) { + pageContext.notifyUnexpectedError(e); + } return true; } diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 0377c5b8..eda924a6 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -1873,6 +1873,7 @@ sebserver.monitoring.exam.connection.action.instruction.quit.all=Quit All SEB Cl sebserver.monitoring.exam.connection.action.instruction.quit.confirm=Are you sure to quit this SEB client connection? sebserver.monitoring.exam.connection.action.instruction.quit.selected.confirm=Are you sure to quit all selected, active SEB client connections? sebserver.monitoring.exam.connection.action.instruction.quit.all.confirm=Are you sure to quit all active SEB client connections? +sebserver.monitoring.exam.connection.action.instruction.lock=Lock SEB Client sebserver.monitoring.exam.connection.action.instruction.lock.selected=Lock Selected SEB Clients sebserver.monitoring.exam.connection.action.instruction.lock.confirm=Are you sure to lock this SEB client connection? sebserver.monitoring.exam.connection.action.instruction.disable.selected.confirm=Are you sure to disable all selected SEB client connections?