fixed quit JSON
This commit is contained in:
parent
857706c7b7
commit
1ecaa132a9
18 changed files with 427 additions and 220 deletions
|
@ -57,6 +57,7 @@ public final class Constants {
|
||||||
public static final Character LIST_SEPARATOR_CHAR = COMMA;
|
public static final Character LIST_SEPARATOR_CHAR = COMMA;
|
||||||
public static final Character COMPLEX_VALUE_SEPARATOR = COLON;
|
public static final Character COMPLEX_VALUE_SEPARATOR = COLON;
|
||||||
|
|
||||||
|
public static final String NULL = "null";
|
||||||
public static final String PERCENTAGE_STRING = Constants.PERCENTAGE.toString();
|
public static final String PERCENTAGE_STRING = Constants.PERCENTAGE.toString();
|
||||||
public static final String LIST_SEPARATOR = COMMA.toString();
|
public static final String LIST_SEPARATOR = COMMA.toString();
|
||||||
public static final String EMBEDDED_LIST_SEPARATOR = PIPE.toString();
|
public static final String EMBEDDED_LIST_SEPARATOR = PIPE.toString();
|
||||||
|
|
|
@ -157,6 +157,7 @@ public final class API {
|
||||||
public static final String EXAM_MONITORING_DISABLE_CONNECTION_ENDPOINT = "/disable-connection";
|
public static final String EXAM_MONITORING_DISABLE_CONNECTION_ENDPOINT = "/disable-connection";
|
||||||
public static final String EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT =
|
public static final String EXAM_MONITORING_SEB_CONNECTION_TOKEN_PATH_SEGMENT =
|
||||||
"/{" + EXAM_API_SEB_CONNECTION_TOKEN + "}";
|
"/{" + EXAM_API_SEB_CONNECTION_TOKEN + "}";
|
||||||
|
public static final String EXAM_MONITORING_STATE_FILTER = "hidden-states";
|
||||||
|
|
||||||
public static final String SEB_CLIENT_CONNECTION_ENDPOINT = "/seb-client-connection";
|
public static final String SEB_CLIENT_CONNECTION_ENDPOINT = "/seb-client-connection";
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.ethz.seb.sebserver.gui.content;
|
||||||
|
|
||||||
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.PageService.PageActionBuilder;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.page.impl.PageAction;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNodePage;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
|
||||||
|
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck;
|
||||||
|
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition;
|
||||||
|
import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
|
||||||
|
import ch.ethz.seb.sebserver.gui.table.EntityTable;
|
||||||
|
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
|
||||||
|
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
|
public class ConfigTemplateList implements TemplateComposer {
|
||||||
|
|
||||||
|
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
|
||||||
|
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
|
||||||
|
private static final LocTextKey TITLE_TEMPLATE_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.configtemplate.list.title");
|
||||||
|
private static final LocTextKey EMPTY_TEMPLATE_LIST_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.configtemplate.list.empty");
|
||||||
|
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.examconfig.list.column.institution");
|
||||||
|
private static final LocTextKey NAME_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.examconfig.list.column.name");
|
||||||
|
private static final LocTextKey DESCRIPTION_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.examconfig.list.column.description");
|
||||||
|
private static final LocTextKey EMPTY_TEMPLATE_SELECTION_TEXT_KEY =
|
||||||
|
new LocTextKey("sebserver.configtemplate.info.pleaseSelect");
|
||||||
|
|
||||||
|
private final PageService pageService;
|
||||||
|
private final RestService restService;
|
||||||
|
private final CurrentUser currentUser;
|
||||||
|
private final ResourceService resourceService;
|
||||||
|
private final int pageSize;
|
||||||
|
|
||||||
|
private final TableFilterAttribute institutionFilter;
|
||||||
|
private final TableFilterAttribute nameFilter =
|
||||||
|
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||||
|
private final TableFilterAttribute descFilter =
|
||||||
|
new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION);
|
||||||
|
|
||||||
|
protected ConfigTemplateList(
|
||||||
|
final PageService pageService,
|
||||||
|
final RestService restService,
|
||||||
|
final CurrentUser currentUser,
|
||||||
|
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||||
|
|
||||||
|
this.pageService = pageService;
|
||||||
|
this.restService = restService;
|
||||||
|
this.currentUser = currentUser;
|
||||||
|
this.resourceService = pageService.getResourceService();
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
|
||||||
|
this.institutionFilter = new TableFilterAttribute(
|
||||||
|
CriteriaType.SINGLE_SELECTION,
|
||||||
|
Entity.FILTER_ATTR_INSTITUTION,
|
||||||
|
this.resourceService::institutionResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void compose(final PageContext pageContext) {
|
||||||
|
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||||
|
final Composite content = widgetFactory.defaultPageLayout(
|
||||||
|
pageContext.getParent(),
|
||||||
|
TITLE_TEMPLATE_TEXT_KEY);
|
||||||
|
|
||||||
|
final boolean isSEBAdmin = this.currentUser.get().hasRole(UserRole.SEB_SERVER_ADMIN);
|
||||||
|
final PageActionBuilder pageActionBuilder =
|
||||||
|
this.pageService.pageActionBuilder(pageContext.clearEntityKeys());
|
||||||
|
|
||||||
|
final EntityTable<ConfigurationNode> templateTable =
|
||||||
|
this.pageService.entityTableBuilder(
|
||||||
|
TITLE_TEMPLATE_TEXT_KEY.name,
|
||||||
|
this.restService.getRestCall(GetExamConfigNodePage.class))
|
||||||
|
.withStaticFilter(
|
||||||
|
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||||
|
ConfigurationType.TEMPLATE.name())
|
||||||
|
.withEmptyMessage(EMPTY_TEMPLATE_LIST_TEXT_KEY)
|
||||||
|
.withPaging(this.pageSize)
|
||||||
|
.withColumnIf(
|
||||||
|
() -> isSEBAdmin,
|
||||||
|
() -> new ColumnDefinition<>(
|
||||||
|
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
||||||
|
INSTITUTION_TEXT_KEY,
|
||||||
|
this.resourceService::localizedExamConfigInstitutionName)
|
||||||
|
.withFilter(this.institutionFilter)
|
||||||
|
.sortable())
|
||||||
|
.withColumn(new ColumnDefinition<>(
|
||||||
|
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
||||||
|
NAME_TEXT_KEY,
|
||||||
|
ConfigurationNode::getName)
|
||||||
|
.withFilter(this.nameFilter)
|
||||||
|
.sortable())
|
||||||
|
.withColumn(new ColumnDefinition<>(
|
||||||
|
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||||
|
DESCRIPTION_TEXT_KEY,
|
||||||
|
ConfigurationNode::getDescription)
|
||||||
|
.withFilter(this.descFilter)
|
||||||
|
.sortable())
|
||||||
|
.withDefaultAction(pageActionBuilder
|
||||||
|
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
|
||||||
|
.create())
|
||||||
|
.compose(pageContext.copyOf(content));
|
||||||
|
|
||||||
|
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
||||||
|
pageActionBuilder
|
||||||
|
// Exam Configuration template actions...
|
||||||
|
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
|
||||||
|
.publishIf(examConfigGrant::iw)
|
||||||
|
|
||||||
|
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
|
||||||
|
.withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
|
||||||
|
EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
|
||||||
|
.publishIf(() -> templateTable.hasAnyContent())
|
||||||
|
|
||||||
|
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST)
|
||||||
|
.withSelect(
|
||||||
|
templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
||||||
|
PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
|
||||||
|
.publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -192,14 +192,21 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
action -> this.disableSebClients(action, clientTable, false),
|
action -> this.disableSebClients(action, clientTable, false),
|
||||||
EMPTY_SELECTION_TEXT_KEY)
|
EMPTY_SELECTION_TEXT_KEY)
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(privilege)
|
.publishIf(privilege);
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
clientTable.hideStatus(ConnectionStatus.DISABLED);
|
|
||||||
|
|
||||||
if (privilege.getAsBoolean()) {
|
if (privilege.getAsBoolean()) {
|
||||||
|
|
||||||
|
if (clientTable.isStatusHidden(ConnectionStatus.CLOSED)) {
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_CLOSED_CONNECTION)
|
||||||
|
.withExec(showStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
||||||
|
.noEventPropagation()
|
||||||
|
.withSwitchAction(
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
|
||||||
|
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
||||||
|
.noEventPropagation()
|
||||||
|
.create())
|
||||||
|
.publish();
|
||||||
|
} else {
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_CLOSED_CONNECTION)
|
||||||
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CLOSED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
|
@ -209,17 +216,33 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.create())
|
.create())
|
||||||
.publish();
|
.publish();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientTable.isStatusHidden(ConnectionStatus.CONNECTION_REQUESTED)) {
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
|
||||||
|
.withExec(showStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
|
||||||
|
.noEventPropagation()
|
||||||
|
.withSwitchAction(
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_REQUESTED_CONNECTION)
|
||||||
|
.withExec(
|
||||||
|
hideStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
|
||||||
|
.noEventPropagation()
|
||||||
|
.create())
|
||||||
|
.publish();
|
||||||
|
} else {
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_REQUESTED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_REQUESTED_CONNECTION)
|
||||||
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
|
.withExec(hideStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.withSwitchAction(
|
.withSwitchAction(
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_REQUESTED_CONNECTION)
|
||||||
.withExec(showStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
|
.withExec(
|
||||||
|
showStateViewAction(clientTable, ConnectionStatus.CONNECTION_REQUESTED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.create())
|
.create())
|
||||||
.publish();
|
.publish();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clientTable.isStatusHidden(ConnectionStatus.DISABLED)) {
|
||||||
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
|
||||||
.withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
.withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
|
@ -229,6 +252,17 @@ public class MonitoringRunningExam implements TemplateComposer {
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.create())
|
.create())
|
||||||
.publish();
|
.publish();
|
||||||
|
} else {
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_HIDE_DISABLED_CONNECTION)
|
||||||
|
.withExec(hideStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
||||||
|
.noEventPropagation()
|
||||||
|
.withSwitchAction(
|
||||||
|
actionBuilder.newAction(ActionDefinition.MONITOR_EXAM_SHOW_DISABLED_CONNECTION)
|
||||||
|
.withExec(showStateViewAction(clientTable, ConnectionStatus.DISABLED))
|
||||||
|
.noEventPropagation()
|
||||||
|
.create())
|
||||||
|
.publish();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
package ch.ethz.seb.sebserver.gui.content;
|
package ch.ethz.seb.sebserver.gui.content;
|
||||||
|
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@ -46,12 +47,8 @@ public class SebExamConfigList implements TemplateComposer {
|
||||||
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
|
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
|
||||||
private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY =
|
private static final LocTextKey EMPTY_CONFIG_LIST_TEXT_KEY =
|
||||||
new LocTextKey("sebserver.examconfig.list.empty");
|
new LocTextKey("sebserver.examconfig.list.empty");
|
||||||
private static final LocTextKey EMPTY_TEMPLATE_LIST_TEXT_KEY =
|
|
||||||
new LocTextKey("sebserver.configtemplate.list.empty");
|
|
||||||
private static final LocTextKey TITLE_CONFIGURATION_TEXT_KEY =
|
private static final LocTextKey TITLE_CONFIGURATION_TEXT_KEY =
|
||||||
new LocTextKey("sebserver.examconfig.list.title");
|
new LocTextKey("sebserver.examconfig.list.title");
|
||||||
private static final LocTextKey TITLE_TEMPLATE_TEXT_KEY =
|
|
||||||
new LocTextKey("sebserver.configtemplate.list.title");
|
|
||||||
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
private static final LocTextKey INSTITUTION_TEXT_KEY =
|
||||||
new LocTextKey("sebserver.examconfig.list.column.institution");
|
new LocTextKey("sebserver.examconfig.list.column.institution");
|
||||||
private static final LocTextKey NAME_TEXT_KEY =
|
private static final LocTextKey NAME_TEXT_KEY =
|
||||||
|
@ -62,28 +59,31 @@ public class SebExamConfigList implements TemplateComposer {
|
||||||
new LocTextKey("sebserver.examconfig.list.column.status");
|
new LocTextKey("sebserver.examconfig.list.column.status");
|
||||||
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
private static final LocTextKey EMPTY_SELECTION_TEXT_KEY =
|
||||||
new LocTextKey("sebserver.examconfig.info.pleaseSelect");
|
new LocTextKey("sebserver.examconfig.info.pleaseSelect");
|
||||||
private static final LocTextKey EMPTY_TEMPLATE_SELECTION_TEXT_KEY =
|
|
||||||
new LocTextKey("sebserver.configtemplate.info.pleaseSelect");
|
|
||||||
|
|
||||||
private final TableFilterAttribute institutionFilter;
|
private final TableFilterAttribute institutionFilter;
|
||||||
private final TableFilterAttribute nameFilter =
|
private final TableFilterAttribute nameFilter =
|
||||||
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME);
|
||||||
|
private final TableFilterAttribute descFilter =
|
||||||
|
new TableFilterAttribute(CriteriaType.TEXT, ConfigurationNode.FILTER_ATTR_DESCRIPTION);
|
||||||
private final TableFilterAttribute statusFilter;
|
private final TableFilterAttribute statusFilter;
|
||||||
|
|
||||||
private final PageService pageService;
|
private final PageService pageService;
|
||||||
private final RestService restService;
|
private final RestService restService;
|
||||||
private final CurrentUser currentUser;
|
private final CurrentUser currentUser;
|
||||||
private final ResourceService resourceService;
|
private final ResourceService resourceService;
|
||||||
|
private final int pageSize;
|
||||||
|
|
||||||
protected SebExamConfigList(
|
protected SebExamConfigList(
|
||||||
final PageService pageService,
|
final PageService pageService,
|
||||||
final RestService restService,
|
final RestService restService,
|
||||||
final CurrentUser currentUser) {
|
final CurrentUser currentUser,
|
||||||
|
@Value("${sebserver.gui.list.page.size:20}") final Integer pageSize) {
|
||||||
|
|
||||||
this.pageService = pageService;
|
this.pageService = pageService;
|
||||||
this.restService = restService;
|
this.restService = restService;
|
||||||
this.currentUser = currentUser;
|
this.currentUser = currentUser;
|
||||||
this.resourceService = pageService.getResourceService();
|
this.resourceService = pageService.getResourceService();
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
|
||||||
this.institutionFilter = new TableFilterAttribute(
|
this.institutionFilter = new TableFilterAttribute(
|
||||||
CriteriaType.SINGLE_SELECTION,
|
CriteriaType.SINGLE_SELECTION,
|
||||||
|
@ -99,7 +99,6 @@ public class SebExamConfigList implements TemplateComposer {
|
||||||
@Override
|
@Override
|
||||||
public void compose(final PageContext pageContext) {
|
public void compose(final PageContext pageContext) {
|
||||||
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
|
||||||
|
|
||||||
final Composite content = widgetFactory.defaultPageLayout(
|
final Composite content = widgetFactory.defaultPageLayout(
|
||||||
pageContext.getParent(),
|
pageContext.getParent(),
|
||||||
TITLE_CONFIGURATION_TEXT_KEY);
|
TITLE_CONFIGURATION_TEXT_KEY);
|
||||||
|
@ -115,7 +114,7 @@ public class SebExamConfigList implements TemplateComposer {
|
||||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
||||||
ConfigurationType.EXAM_CONFIG.name())
|
ConfigurationType.EXAM_CONFIG.name())
|
||||||
.withEmptyMessage(EMPTY_CONFIG_LIST_TEXT_KEY)
|
.withEmptyMessage(EMPTY_CONFIG_LIST_TEXT_KEY)
|
||||||
.withPaging(6)
|
.withPaging(this.pageSize)
|
||||||
.withColumnIf(
|
.withColumnIf(
|
||||||
() -> isSEBAdmin,
|
() -> isSEBAdmin,
|
||||||
() -> new ColumnDefinition<>(
|
() -> new ColumnDefinition<>(
|
||||||
|
@ -134,7 +133,7 @@ public class SebExamConfigList implements TemplateComposer {
|
||||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
||||||
DESCRIPTION_TEXT_KEY,
|
DESCRIPTION_TEXT_KEY,
|
||||||
ConfigurationNode::getDescription)
|
ConfigurationNode::getDescription)
|
||||||
.withFilter(this.nameFilter)
|
.withFilter(this.descFilter)
|
||||||
.sortable())
|
.sortable())
|
||||||
.withColumn(new ColumnDefinition<ConfigurationNode>(
|
.withColumn(new ColumnDefinition<ConfigurationNode>(
|
||||||
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
Domain.CONFIGURATION_NODE.ATTR_STATUS,
|
||||||
|
@ -147,45 +146,6 @@ public class SebExamConfigList implements TemplateComposer {
|
||||||
.create())
|
.create())
|
||||||
.compose(pageContext.copyOf(content));
|
.compose(pageContext.copyOf(content));
|
||||||
|
|
||||||
// configuration template table
|
|
||||||
widgetFactory.label(content, "");
|
|
||||||
widgetFactory.labelLocalizedTitle(
|
|
||||||
content,
|
|
||||||
TITLE_TEMPLATE_TEXT_KEY);
|
|
||||||
widgetFactory.labelSeparator(content);
|
|
||||||
|
|
||||||
final EntityTable<ConfigurationNode> templateTable =
|
|
||||||
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class))
|
|
||||||
.withStaticFilter(
|
|
||||||
Domain.CONFIGURATION_NODE.ATTR_TYPE,
|
|
||||||
ConfigurationType.TEMPLATE.name())
|
|
||||||
.withEmptyMessage(EMPTY_TEMPLATE_LIST_TEXT_KEY)
|
|
||||||
.withPaging(6)
|
|
||||||
.withColumnIf(
|
|
||||||
() -> isSEBAdmin,
|
|
||||||
() -> new ColumnDefinition<>(
|
|
||||||
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
|
|
||||||
INSTITUTION_TEXT_KEY,
|
|
||||||
this.resourceService::localizedExamConfigInstitutionName)
|
|
||||||
.withFilter(this.institutionFilter)
|
|
||||||
.sortable())
|
|
||||||
.withColumn(new ColumnDefinition<>(
|
|
||||||
Domain.CONFIGURATION_NODE.ATTR_NAME,
|
|
||||||
NAME_TEXT_KEY,
|
|
||||||
ConfigurationNode::getName)
|
|
||||||
.withFilter(this.nameFilter)
|
|
||||||
.sortable())
|
|
||||||
.withColumn(new ColumnDefinition<>(
|
|
||||||
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
|
|
||||||
DESCRIPTION_TEXT_KEY,
|
|
||||||
ConfigurationNode::getDescription)
|
|
||||||
.withFilter(this.nameFilter)
|
|
||||||
.sortable())
|
|
||||||
.withDefaultAction(pageActionBuilder
|
|
||||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
|
|
||||||
.create())
|
|
||||||
.compose(pageContext.copyOf(content));
|
|
||||||
|
|
||||||
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
|
||||||
pageActionBuilder
|
pageActionBuilder
|
||||||
// Exam Configuration actions...
|
// Exam Configuration actions...
|
||||||
|
@ -214,20 +174,7 @@ public class SebExamConfigList implements TemplateComposer {
|
||||||
.noEventPropagation()
|
.noEventPropagation()
|
||||||
.publishIf(() -> examConfigGrant.im())
|
.publishIf(() -> examConfigGrant.im())
|
||||||
|
|
||||||
// Exam Configuration template actions...
|
;
|
||||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_NEW)
|
|
||||||
.publishIf(examConfigGrant::iw)
|
|
||||||
|
|
||||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
|
|
||||||
.withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
|
|
||||||
EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
|
|
||||||
.publishIf(() -> templateTable.hasAnyContent())
|
|
||||||
|
|
||||||
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST)
|
|
||||||
.withSelect(
|
|
||||||
templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
|
|
||||||
PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
|
|
||||||
.publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ public enum ActionCategory {
|
||||||
INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2),
|
INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2),
|
||||||
SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1),
|
SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1),
|
||||||
SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1),
|
SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1),
|
||||||
SEB_CONFIG_TEMPLATE_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 2),
|
SEB_CONFIG_TEMPLATE_LIST(new LocTextKey("sebserver.configtemplate.list.actions"), 1),
|
||||||
SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.list.actions"), 1),
|
SEB_CONFIG_TEMPLATE_ATTRIBUTE_LIST(new LocTextKey("sebserver.configtemplate.attr.list.actions"), 1),
|
||||||
RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1),
|
RUNNING_EXAM_LIST(new LocTextKey("sebserver.monitoring.exam.list.actions"), 1),
|
||||||
CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.list.actions"), 1),
|
CLIENT_EVENT_LIST(new LocTextKey("sebserver.monitoring.exam.connection.list.actions"), 1),
|
||||||
|
|
|
@ -467,6 +467,9 @@ public enum ActionDefinition {
|
||||||
PageStateDefinitionImpl.SEB_EXAM_CONFIG_EDIT,
|
PageStateDefinitionImpl.SEB_EXAM_CONFIG_EDIT,
|
||||||
ActionCategory.FORM),
|
ActionCategory.FORM),
|
||||||
|
|
||||||
|
SEB_EXAM_CONFIG_TEMPLATE_LIST(
|
||||||
|
new LocTextKey("sebserver.configtemplate.action.list"),
|
||||||
|
PageStateDefinitionImpl.SEB_EXAM_CONFIG_TEMPLATE_LIST),
|
||||||
SEB_EXAM_CONFIG_TEMPLATE_NEW(
|
SEB_EXAM_CONFIG_TEMPLATE_NEW(
|
||||||
new LocTextKey("sebserver.configtemplate.action.list.new"),
|
new LocTextKey("sebserver.configtemplate.action.list.new"),
|
||||||
ImageIcon.TEMPLATE,
|
ImageIcon.TEMPLATE,
|
||||||
|
|
|
@ -214,6 +214,18 @@ public class ActivitiesPane implements TemplateComposer {
|
||||||
.create());
|
.create());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SEB Exam Config Template
|
||||||
|
if (examConfigRead) {
|
||||||
|
final TreeItem examConfigTemplate = this.widgetFactory.treeItemLocalized(
|
||||||
|
sebConfigs,
|
||||||
|
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE.displayName);
|
||||||
|
injectActivitySelection(
|
||||||
|
examConfigTemplate,
|
||||||
|
actionBuilder
|
||||||
|
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_LIST)
|
||||||
|
.create());
|
||||||
|
}
|
||||||
|
|
||||||
sebConfigs.setExpanded(this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN));
|
sebConfigs.setExpanded(this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ public enum ActivityDefinition implements Activity {
|
||||||
SEB_CONFIGURATION(new LocTextKey("sebserver.overall.activity.title.sebconfig")),
|
SEB_CONFIGURATION(new LocTextKey("sebserver.overall.activity.title.sebconfig")),
|
||||||
SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")),
|
SEB_CLIENT_CONFIG(new LocTextKey("sebserver.clientconfig.action.list")),
|
||||||
SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")),
|
SEB_EXAM_CONFIG(new LocTextKey("sebserver.examconfig.action.list")),
|
||||||
|
SEB_EXAM_CONFIG_TEMPLATE(new LocTextKey("sebserver.configtemplate.action.list")),
|
||||||
MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")),
|
MONITORING(new LocTextKey("sebserver.overall.activity.title.monitoring")),
|
||||||
MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")),
|
MONITORING_EXAMS(new LocTextKey("sebserver.monitoring.action.list")),
|
||||||
SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs"));
|
SEB_CLIENT_LOGS(new LocTextKey("sebserver.logs.activity.seblogs"));
|
||||||
|
|
|
@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.gui.content.activity;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateAttributeForm;
|
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateAttributeForm;
|
||||||
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateForm;
|
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateForm;
|
||||||
|
import ch.ethz.seb.sebserver.gui.content.ConfigTemplateList;
|
||||||
import ch.ethz.seb.sebserver.gui.content.ExamForm;
|
import ch.ethz.seb.sebserver.gui.content.ExamForm;
|
||||||
import ch.ethz.seb.sebserver.gui.content.ExamList;
|
import ch.ethz.seb.sebserver.gui.content.ExamList;
|
||||||
import ch.ethz.seb.sebserver.gui.content.IndicatorForm;
|
import ch.ethz.seb.sebserver.gui.content.IndicatorForm;
|
||||||
|
@ -68,8 +69,12 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
|
||||||
SEB_EXAM_CONFIG_EDIT(Type.FORM_IN_TIME_EDIT, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
|
SEB_EXAM_CONFIG_EDIT(Type.FORM_IN_TIME_EDIT, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
|
||||||
SEB_EXAM_CONFIG_VIEW(Type.FORM_VIEW, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
|
SEB_EXAM_CONFIG_VIEW(Type.FORM_VIEW, SebExamConfigSettingsForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
|
||||||
|
|
||||||
SEB_EXAM_CONFIG_TEMPLATE_VIEW(Type.FORM_VIEW, ConfigTemplateForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
|
SEB_EXAM_CONFIG_TEMPLATE_LIST(Type.LIST_VIEW, ConfigTemplateList.class,
|
||||||
SEB_EXAM_CONFIG_TEMPLATE_EDIT(Type.FORM_EDIT, ConfigTemplateForm.class, ActivityDefinition.SEB_EXAM_CONFIG),
|
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||||
|
SEB_EXAM_CONFIG_TEMPLATE_VIEW(Type.FORM_VIEW, ConfigTemplateForm.class,
|
||||||
|
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||||
|
SEB_EXAM_CONFIG_TEMPLATE_EDIT(Type.FORM_EDIT, ConfigTemplateForm.class,
|
||||||
|
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
|
||||||
|
|
||||||
SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_EDIT(
|
SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_EDIT(
|
||||||
Type.FORM_EDIT,
|
Type.FORM_EDIT,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
package ch.ethz.seb.sebserver.gui.service.session;
|
package ch.ethz.seb.sebserver.gui.service.session;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -65,6 +66,7 @@ public final class ClientConnectionTable {
|
||||||
|
|
||||||
private static final int BOTTOM_PADDING = 20;
|
private static final int BOTTOM_PADDING = 20;
|
||||||
private static final int NUMBER_OF_NONE_INDICATOR_COLUMNS = 3;
|
private static final int NUMBER_OF_NONE_INDICATOR_COLUMNS = 3;
|
||||||
|
private static final String USER_SESSION_STATUS_FILTER_ATTRIBUTE = "USER_SESSION_STATUS_FILTER_ATTRIBUTE";
|
||||||
|
|
||||||
private static final String INDICATOR_NAME_TEXT_KEY_PREFIX =
|
private static final String INDICATOR_NAME_TEXT_KEY_PREFIX =
|
||||||
"sebserver.monitoring.connection.list.column.indicator.";
|
"sebserver.monitoring.connection.list.column.indicator.";
|
||||||
|
@ -117,6 +119,7 @@ public final class ClientConnectionTable {
|
||||||
NUMBER_OF_NONE_INDICATOR_COLUMNS);
|
NUMBER_OF_NONE_INDICATOR_COLUMNS);
|
||||||
|
|
||||||
this.statusFilter = EnumSet.noneOf(ConnectionStatus.class);
|
this.statusFilter = EnumSet.noneOf(ConnectionStatus.class);
|
||||||
|
loadStatusFilter();
|
||||||
|
|
||||||
this.table = this.widgetFactory.tableLocalized(tableRoot, SWT.MULTI | SWT.V_SCROLL);
|
this.table = this.widgetFactory.tableLocalized(tableRoot, SWT.MULTI | SWT.V_SCROLL);
|
||||||
final GridLayout gridLayout = new GridLayout(3 + indicators.size(), true);
|
final GridLayout gridLayout = new GridLayout(3 + indicators.size(), true);
|
||||||
|
@ -169,10 +172,45 @@ public final class ClientConnectionTable {
|
||||||
|
|
||||||
public void hideStatus(final ConnectionStatus status) {
|
public void hideStatus(final ConnectionStatus status) {
|
||||||
this.statusFilter.add(status);
|
this.statusFilter.add(status);
|
||||||
|
saveStatusFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showStatus(final ConnectionStatus status) {
|
public void showStatus(final ConnectionStatus status) {
|
||||||
this.statusFilter.remove(status);
|
this.statusFilter.remove(status);
|
||||||
|
saveStatusFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveStatusFilter() {
|
||||||
|
try {
|
||||||
|
this.resourceService
|
||||||
|
.getCurrentUser()
|
||||||
|
.putAttribute(
|
||||||
|
USER_SESSION_STATUS_FILTER_ATTRIBUTE,
|
||||||
|
StringUtils.join(this.statusFilter, Constants.LIST_SEPARATOR));
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to save status filter to user session");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadStatusFilter() {
|
||||||
|
try {
|
||||||
|
final String attribute = this.resourceService
|
||||||
|
.getCurrentUser()
|
||||||
|
.getAttribute(USER_SESSION_STATUS_FILTER_ATTRIBUTE);
|
||||||
|
if (attribute != null) {
|
||||||
|
this.statusFilter.clear();
|
||||||
|
Arrays.asList(StringUtils.split(attribute, Constants.LIST_SEPARATOR))
|
||||||
|
.forEach(name -> this.statusFilter.add(ConnectionStatus.valueOf(name)));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.statusFilter.clear();
|
||||||
|
this.statusFilter.add(ConnectionStatus.DISABLED);
|
||||||
|
}
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to load status filter to user session");
|
||||||
|
this.statusFilter.clear();
|
||||||
|
this.statusFilter.add(ConnectionStatus.DISABLED);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void withDefaultAction(final PageAction pageAction, final PageService pageService) {
|
public void withDefaultAction(final PageAction pageAction, final PageService pageService) {
|
||||||
|
|
|
@ -10,52 +10,45 @@ package ch.ethz.seb.sebserver.gui.widget;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Map.Entry;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.eclipse.rap.rwt.widgets.DropDown;
|
||||||
import org.eclipse.swt.SWT;
|
import org.eclipse.swt.SWT;
|
||||||
import org.eclipse.swt.layout.GridData;
|
import org.eclipse.swt.layout.GridData;
|
||||||
import org.eclipse.swt.layout.GridLayout;
|
import org.eclipse.swt.layout.GridLayout;
|
||||||
import org.eclipse.swt.widgets.Combo;
|
|
||||||
import org.eclipse.swt.widgets.Composite;
|
import org.eclipse.swt.widgets.Composite;
|
||||||
import org.eclipse.swt.widgets.Control;
|
import org.eclipse.swt.widgets.Control;
|
||||||
import org.eclipse.swt.widgets.Event;
|
import org.eclipse.swt.widgets.Event;
|
||||||
import org.eclipse.swt.widgets.Label;
|
import org.eclipse.swt.widgets.Label;
|
||||||
import org.eclipse.swt.widgets.Listener;
|
import org.eclipse.swt.widgets.Listener;
|
||||||
|
import org.eclipse.swt.widgets.Text;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
|
||||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
|
||||||
|
|
||||||
public final class MultiSelectionCombo extends Composite implements Selection {
|
public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MultiSelectionCombo.class);
|
private static final Logger log = LoggerFactory.getLogger(MultiSelectionCombo.class);
|
||||||
private static final long serialVersionUID = -7787134114963647332L;
|
private static final long serialVersionUID = -7787134114963647332L;
|
||||||
private static final int ACTION_COLUMN_WIDTH = 20;
|
|
||||||
|
|
||||||
private static final LocTextKey DEFAULT_ADD_TOOLTIP_KEY = new LocTextKey("sebserver.overall.add");
|
|
||||||
private static final LocTextKey DEFAULT_REMOVE_TOOLTIP_KEY = new LocTextKey("sebserver.overall.remove");
|
|
||||||
|
|
||||||
private final WidgetFactory widgetFactory;
|
private final WidgetFactory widgetFactory;
|
||||||
private final Combo combo;
|
|
||||||
private final LocTextKey addTextKey;
|
|
||||||
private final LocTextKey removeTextKey;
|
|
||||||
|
|
||||||
private final List<Tuple<Control>> selectionControls = new ArrayList<>();
|
private final List<Control> selectionControls = new ArrayList<>();
|
||||||
|
|
||||||
|
private final List<Tuple<String>> valueMapping = new ArrayList<>();
|
||||||
|
private final List<Tuple<String>> availableValues = new ArrayList<>();
|
||||||
private final List<Tuple<String>> selectedValues = new ArrayList<>();
|
private final List<Tuple<String>> selectedValues = new ArrayList<>();
|
||||||
private final Map<String, String> mapping = new HashMap<>();
|
|
||||||
|
|
||||||
private final GridData comboCell;
|
private final DropDown dropDown;
|
||||||
private final GridData actionCell;
|
private final Text textInput;
|
||||||
|
private final GridData textCell;
|
||||||
private final Composite updateAnchor;
|
private final Composite updateAnchor;
|
||||||
|
|
||||||
private Listener listener = null;
|
private Listener listener = null;
|
||||||
|
@ -68,14 +61,8 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
|
|
||||||
super(parent, SWT.NONE);
|
super(parent, SWT.NONE);
|
||||||
this.widgetFactory = widgetFactory;
|
this.widgetFactory = widgetFactory;
|
||||||
this.addTextKey = (locTextPrefix != null)
|
|
||||||
? new LocTextKey(locTextPrefix + ".add")
|
|
||||||
: DEFAULT_ADD_TOOLTIP_KEY;
|
|
||||||
this.removeTextKey = (locTextPrefix != null)
|
|
||||||
? new LocTextKey(locTextPrefix + ".remove")
|
|
||||||
: DEFAULT_REMOVE_TOOLTIP_KEY;
|
|
||||||
|
|
||||||
final GridLayout gridLayout = new GridLayout(2, false);
|
final GridLayout gridLayout = new GridLayout();
|
||||||
gridLayout.verticalSpacing = 1;
|
gridLayout.verticalSpacing = 1;
|
||||||
gridLayout.marginLeft = 0;
|
gridLayout.marginLeft = 0;
|
||||||
gridLayout.marginHeight = 0;
|
gridLayout.marginHeight = 0;
|
||||||
|
@ -84,22 +71,43 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
setLayout(gridLayout);
|
setLayout(gridLayout);
|
||||||
|
|
||||||
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||||
|
this.textInput = widgetFactory.textInput(this);
|
||||||
|
this.textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
||||||
|
this.textInput.setLayoutData(this.textCell);
|
||||||
|
this.dropDown = new DropDown(this.textInput, SWT.NONE);
|
||||||
|
this.textInput.addListener(SWT.FocusIn, event -> {
|
||||||
|
openDropDown();
|
||||||
|
});
|
||||||
|
this.textInput.addListener(SWT.Modify, event -> {
|
||||||
|
openDropDown();
|
||||||
|
});
|
||||||
|
this.dropDown.addListener(SWT.Selection, event -> {
|
||||||
|
final int selectionIndex = this.dropDown.getSelectionIndex();
|
||||||
|
if (selectionIndex >= 0) {
|
||||||
|
final String selectedItem = this.dropDown.getItems()[selectionIndex];
|
||||||
|
addSelection(itemForName(selectedItem));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.combo = new Combo(this, SWT.NONE);
|
|
||||||
this.comboCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
|
||||||
this.combo.setLayoutData(this.comboCell);
|
|
||||||
|
|
||||||
final Label imageButton = widgetFactory.imageButton(
|
|
||||||
ImageIcon.ADD_BOX,
|
|
||||||
this,
|
|
||||||
this.addTextKey,
|
|
||||||
this::addComboSelection);
|
|
||||||
this.actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
|
||||||
this.actionCell.widthHint = ACTION_COLUMN_WIDTH;
|
|
||||||
imageButton.setLayoutData(this.actionCell);
|
|
||||||
this.updateAnchor = updateAnchor;
|
this.updateAnchor = updateAnchor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void openDropDown() {
|
||||||
|
final String text = this.textInput.getText();
|
||||||
|
if (text == null) {
|
||||||
|
this.dropDown.setVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final Collection<String> items = this.availableValues
|
||||||
|
.stream()
|
||||||
|
.filter(it -> it._2 != null && it._2.startsWith(text))
|
||||||
|
.map(t -> t._2)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
this.dropDown.setItems(items.toArray(new String[items.size()]));
|
||||||
|
this.dropDown.setSelectionIndex(0);
|
||||||
|
this.dropDown.setVisible(true);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Type type() {
|
public Type type() {
|
||||||
return Type.MULTI_COMBO;
|
return Type.MULTI_COMBO;
|
||||||
|
@ -112,8 +120,8 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
public void applyNewMapping(final List<Tuple<String>> mapping) {
|
||||||
this.mapping.putAll(mapping.stream()
|
this.valueMapping.clear();
|
||||||
.collect(Collectors.toMap(t -> t._1, t -> t._2)));
|
this.valueMapping.addAll(mapping);
|
||||||
this.clear();
|
this.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,9 +134,22 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
|
|
||||||
Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR))
|
Arrays.asList(StringUtils.split(keys, Constants.LIST_SEPARATOR))
|
||||||
.stream()
|
.stream()
|
||||||
|
.map(this::itemForName)
|
||||||
.forEach(this::addSelection);
|
.forEach(this::addSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Tuple<String> itemForName(final String name) {
|
||||||
|
final Optional<Tuple<String>> findFirst = this.availableValues
|
||||||
|
.stream()
|
||||||
|
.filter(it -> it._2 != null && it._2.equals(name))
|
||||||
|
.findFirst();
|
||||||
|
if (findFirst.isPresent()) {
|
||||||
|
return findFirst.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSelectionValue() {
|
public String getSelectionValue() {
|
||||||
if (this.selectedValues.isEmpty()) {
|
if (this.selectedValues.isEmpty()) {
|
||||||
|
@ -151,61 +172,28 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
this.selectedValues.clear();
|
this.selectedValues.clear();
|
||||||
this.selectionControls
|
this.selectionControls
|
||||||
.stream()
|
.stream()
|
||||||
.forEach(t -> {
|
.forEach(Control::dispose);
|
||||||
t._1.dispose();
|
|
||||||
t._2.dispose();
|
|
||||||
});
|
|
||||||
this.selectionControls.clear();
|
this.selectionControls.clear();
|
||||||
this.combo.setItems(this.mapping.values().toArray(new String[this.mapping.size()]));
|
this.availableValues.clear();
|
||||||
|
this.availableValues.addAll(this.valueMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addComboSelection(final Event event) {
|
private void addSelection(final Tuple<String> item) {
|
||||||
final int selectionIndex = this.combo.getSelectionIndex();
|
if (item == null) {
|
||||||
if (selectionIndex < 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String itemName = this.combo.getItem(selectionIndex);
|
this.selectedValues.add(item);
|
||||||
if (itemName == null) {
|
final Label label = this.widgetFactory.label(this, item._2);
|
||||||
return;
|
label.setData(OPTION_VALUE, item._2);
|
||||||
}
|
final GridData textCell = new GridData(SWT.LEFT, SWT.CENTER, true, true);
|
||||||
|
label.setLayoutData(textCell);
|
||||||
|
label.addListener(SWT.MouseDoubleClick, event -> {
|
||||||
|
removeComboSelection(event);
|
||||||
|
});
|
||||||
|
this.selectionControls.add(label);
|
||||||
|
|
||||||
final Optional<Entry<String, String>> findFirst = this.mapping.entrySet()
|
this.availableValues.remove(item);
|
||||||
.stream()
|
|
||||||
.filter(entity -> entity.getValue().equals(itemName))
|
|
||||||
.findFirst();
|
|
||||||
|
|
||||||
if (!findFirst.isPresent()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
addSelection(findFirst.get().getKey());
|
|
||||||
if (this.listener != null) {
|
|
||||||
this.listener.handleEvent(event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSelection(final String itemKey) {
|
|
||||||
final String itemName = this.mapping.get(itemKey);
|
|
||||||
if (itemName == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.selectedValues.add(new Tuple<>(itemKey, itemName));
|
|
||||||
final Label label = this.widgetFactory.label(this, itemName);
|
|
||||||
final Label imageButton = this.widgetFactory.imageButton(
|
|
||||||
ImageIcon.REMOVE_BOX,
|
|
||||||
this,
|
|
||||||
this.removeTextKey,
|
|
||||||
this::removeComboSelection);
|
|
||||||
imageButton.setData(OPTION_VALUE, itemName);
|
|
||||||
final GridData actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
|
||||||
actionCell.widthHint = ACTION_COLUMN_WIDTH;
|
|
||||||
imageButton.setLayoutData(actionCell);
|
|
||||||
|
|
||||||
this.selectionControls.add(new Tuple<>(label, imageButton));
|
|
||||||
|
|
||||||
this.combo.remove(itemName);
|
|
||||||
PageService.updateScrolledComposite(this);
|
PageService.updateScrolledComposite(this);
|
||||||
this.updateAnchor.layout(true, true);
|
this.updateAnchor.layout(true, true);
|
||||||
|
|
||||||
|
@ -217,22 +205,20 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
}
|
}
|
||||||
|
|
||||||
final String selectionKey = (String) event.widget.getData(OPTION_VALUE);
|
final String selectionKey = (String) event.widget.getData(OPTION_VALUE);
|
||||||
final Optional<Tuple<Control>> findFirst = this.selectionControls.stream()
|
final Optional<Control> findFirst = this.selectionControls.stream()
|
||||||
.filter(t -> selectionKey.equals(t._2.getData(OPTION_VALUE)))
|
.filter(t -> selectionKey.equals(t.getData(OPTION_VALUE)))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
if (!findFirst.isPresent()) {
|
if (!findFirst.isPresent()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Tuple<Control> tuple = findFirst.get();
|
final Control control = findFirst.get();
|
||||||
final int indexOf = this.selectionControls.indexOf(tuple);
|
final int indexOf = this.selectionControls.indexOf(control);
|
||||||
this.selectionControls.remove(tuple);
|
this.selectionControls.remove(control);
|
||||||
|
control.dispose();
|
||||||
tuple._1.dispose();
|
|
||||||
tuple._2.dispose();
|
|
||||||
|
|
||||||
final Tuple<String> value = this.selectedValues.remove(indexOf);
|
final Tuple<String> value = this.selectedValues.remove(indexOf);
|
||||||
this.combo.add(value._2, this.combo.getItemCount());
|
this.availableValues.add(value);
|
||||||
|
|
||||||
PageService.updateScrolledComposite(this);
|
PageService.updateScrolledComposite(this);
|
||||||
this.updateAnchor.layout(true, true);
|
this.updateAnchor.layout(true, true);
|
||||||
|
@ -244,7 +230,7 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
||||||
private void adaptColumnWidth(final Event event) {
|
private void adaptColumnWidth(final Event event) {
|
||||||
try {
|
try {
|
||||||
final int currentTableWidth = this.getClientArea().width;
|
final int currentTableWidth = this.getClientArea().width;
|
||||||
this.comboCell.widthHint = currentTableWidth - ACTION_COLUMN_WIDTH;
|
this.textCell.widthHint = currentTableWidth;
|
||||||
this.layout();
|
this.layout();
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn("Failed to adaptColumnWidth: ", e);
|
log.warn("Failed to adaptColumnWidth: ", e);
|
||||||
|
|
|
@ -136,9 +136,12 @@ public interface ExamSessionService {
|
||||||
* a subset of them.
|
* a subset of them.
|
||||||
*
|
*
|
||||||
* @param examId The exam identifier
|
* @param examId The exam identifier
|
||||||
|
* @param filter a filter predicate to apply
|
||||||
* @return collection of ClientConnectionData of all active SEB client connections
|
* @return collection of ClientConnectionData of all active SEB client connections
|
||||||
* of a running exam */
|
* of a running exam */
|
||||||
Result<Collection<ClientConnectionData>> getConnectionData(Long examId);
|
Result<Collection<ClientConnectionData>> getConnectionData(
|
||||||
|
Long examId,
|
||||||
|
Predicate<ClientConnectionData> filter);
|
||||||
|
|
||||||
/** Use this to check if the current cached running exam is up to date
|
/** Use this to check if the current cached running exam is up to date
|
||||||
* and if not to flush the cache.
|
* and if not to flush the cache.
|
||||||
|
|
|
@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
@ -224,12 +225,7 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkActiveClientConnections(final Exam exam) {
|
private void checkActiveClientConnections(final Exam exam) {
|
||||||
if (this.examSessionService.getConnectionData(exam.id)
|
if (this.examSessionService.hasActiveSebClientConnections(exam.id)) {
|
||||||
.getOrThrow()
|
|
||||||
.stream()
|
|
||||||
.filter(ExamSessionService::isActiveConnection)
|
|
||||||
.count() > 0) {
|
|
||||||
|
|
||||||
throw new APIMessage.APIMessageException(
|
throw new APIMessage.APIMessageException(
|
||||||
ErrorMessage.INTEGRITY_VALIDATION,
|
ErrorMessage.INTEGRITY_VALIDATION,
|
||||||
"Integrity violation: There are currently active SEB Client connection.");
|
"Integrity violation: There are currently active SEB Client connection.");
|
||||||
|
@ -286,7 +282,7 @@ public class ExamConfigUpdateServiceImpl implements ExamConfigUpdateService {
|
||||||
final long activeConnections = involvedExams
|
final long activeConnections = involvedExams
|
||||||
.stream()
|
.stream()
|
||||||
.flatMap(examId -> {
|
.flatMap(examId -> {
|
||||||
return this.examSessionService.getConnectionData(examId)
|
return this.examSessionService.getConnectionData(examId, Objects::nonNull)
|
||||||
.getOrThrow()
|
.getOrThrow()
|
||||||
.stream();
|
.stream();
|
||||||
})
|
})
|
||||||
|
|
|
@ -164,12 +164,9 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getConnectionData(examId)
|
return !this.getConnectionData(examId, ExamSessionService::isActiveConnection)
|
||||||
.getOrThrow()
|
.getOrThrow()
|
||||||
.stream()
|
.isEmpty();
|
||||||
.filter(ExamSessionService::isActiveConnection)
|
|
||||||
.findFirst()
|
|
||||||
.isPresent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -313,14 +310,17 @@ public class ExamSessionServiceImpl implements ExamSessionService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Result<Collection<ClientConnectionData>> getConnectionData(final Long examId) {
|
public Result<Collection<ClientConnectionData>> getConnectionData(
|
||||||
|
final Long examId,
|
||||||
|
final Predicate<ClientConnectionData> filter) {
|
||||||
|
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
return this.clientConnectionDAO
|
return this.clientConnectionDAO
|
||||||
.getConnectionTokens(examId)
|
.getConnectionTokens(examId)
|
||||||
.getOrThrow()
|
.getOrThrow()
|
||||||
.stream()
|
.stream()
|
||||||
.map(this.examSessionCacheService::getActiveClientConnection)
|
.map(this.examSessionCacheService::getActiveClientConnection)
|
||||||
.filter(data -> data != null)
|
.filter(filter)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,8 +123,9 @@ public class SebInstructionServiceImpl implements SebInstructionService {
|
||||||
log.error("Failed to delete SEB client instruction on persistent storage: ", delete.getError());
|
log.error("Failed to delete SEB client instruction on persistent storage: ", delete.getError());
|
||||||
}
|
}
|
||||||
|
|
||||||
// {"instruction":"%s", "attributes":{%s}}
|
// {"instruction":"%s", "attributes":%s}
|
||||||
return new StringBuilder()
|
final String attributes = clientInstruction.getAttributes();
|
||||||
|
final StringBuilder sBuilder = new StringBuilder()
|
||||||
.append(Constants.CURLY_BRACE_OPEN)
|
.append(Constants.CURLY_BRACE_OPEN)
|
||||||
.append(Constants.DOUBLE_QUOTE)
|
.append(Constants.DOUBLE_QUOTE)
|
||||||
.append(JSON_INST)
|
.append(JSON_INST)
|
||||||
|
@ -137,10 +138,16 @@ public class SebInstructionServiceImpl implements SebInstructionService {
|
||||||
.append(Constants.DOUBLE_QUOTE)
|
.append(Constants.DOUBLE_QUOTE)
|
||||||
.append(JSON_ATTR)
|
.append(JSON_ATTR)
|
||||||
.append(Constants.DOUBLE_QUOTE)
|
.append(Constants.DOUBLE_QUOTE)
|
||||||
.append(Constants.COLON)
|
.append(Constants.COLON);
|
||||||
.append(Constants.CURLY_BRACE_OPEN)
|
if (attributes == null || attributes.isEmpty()) {
|
||||||
.append(clientInstruction.getAttributes())
|
sBuilder.append(Constants.NULL);
|
||||||
.append(Constants.CURLY_BRACE_CLOSE)
|
|
||||||
|
} else {
|
||||||
|
sBuilder.append(Constants.CURLY_BRACE_OPEN)
|
||||||
|
.append(attributes)
|
||||||
|
.append(Constants.CURLY_BRACE_CLOSE);
|
||||||
|
}
|
||||||
|
return sBuilder
|
||||||
.append(Constants.CURLY_BRACE_CLOSE)
|
.append(Constants.CURLY_BRACE_CLOSE)
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,9 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
|
|
||||||
|
@ -23,6 +25,7 @@ import org.springframework.web.bind.WebDataBinder;
|
||||||
import org.springframework.web.bind.annotation.InitBinder;
|
import org.springframework.web.bind.annotation.InitBinder;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
@ -35,6 +38,7 @@ import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
|
@ -153,7 +157,8 @@ public class ExamMonitoringController {
|
||||||
name = API.PARAM_INSTITUTION_ID,
|
name = API.PARAM_INSTITUTION_ID,
|
||||||
required = true,
|
required = true,
|
||||||
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
|
||||||
@PathVariable(name = API.PARAM_MODEL_ID, required = true) final Long examId) {
|
@PathVariable(name = API.PARAM_MODEL_ID, required = true) final Long examId,
|
||||||
|
@RequestHeader(name = API.EXAM_MONITORING_STATE_FILTER, required = false) final String hiddenStates) {
|
||||||
|
|
||||||
// check overall privilege
|
// check overall privilege
|
||||||
this.authorization.checkRole(
|
this.authorization.checkRole(
|
||||||
|
@ -169,8 +174,20 @@ public class ExamMonitoringController {
|
||||||
this.authorization.getUserService().getCurrentUser().getUserInfo());
|
this.authorization.getUserService().getCurrentUser().getUserInfo());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final EnumSet<ConnectionStatus> filterStates = EnumSet.noneOf(ConnectionStatus.class);
|
||||||
|
if (StringUtils.isNoneBlank(hiddenStates)) {
|
||||||
|
final String[] split = StringUtils.split(hiddenStates, Constants.LIST_SEPARATOR);
|
||||||
|
for (int i = 0; i < split.length; i++) {
|
||||||
|
filterStates.add(ConnectionStatus.valueOf(split[0]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return this.examSessionService
|
return this.examSessionService
|
||||||
.getConnectionData(examId)
|
.getConnectionData(
|
||||||
|
examId,
|
||||||
|
filterStates.isEmpty()
|
||||||
|
? Objects::nonNull
|
||||||
|
: conn -> conn != null && filterStates.contains(conn.clientConnection.status))
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ sebserver.overall.action.cancel=Cancel
|
||||||
sebserver.overall.action.close=Close
|
sebserver.overall.action.close=Close
|
||||||
sebserver.overall.action.goAwayFromEditPageConfirm=Are you sure you want to leave this page? Unsaved data will be lost.
|
sebserver.overall.action.goAwayFromEditPageConfirm=Are you sure you want to leave this page? Unsaved data will be lost.
|
||||||
sebserver.overall.action.category.varia=
|
sebserver.overall.action.category.varia=
|
||||||
sebserver.overall.action.category.filter=Connection Status Filter
|
sebserver.overall.action.category.filter=
|
||||||
|
|
||||||
sebserver.overall.status.active=Active
|
sebserver.overall.status.active=Active
|
||||||
sebserver.overall.status.inactive=Inactive
|
sebserver.overall.status.inactive=Inactive
|
||||||
|
@ -380,7 +380,7 @@ sebserver.exam.status.UP_COMING=Up Coming
|
||||||
sebserver.exam.status.RUNNING=Running
|
sebserver.exam.status.RUNNING=Running
|
||||||
sebserver.exam.status.FINISHED=Finished
|
sebserver.exam.status.FINISHED=Finished
|
||||||
|
|
||||||
sebserver.exam.configuration.list.actions=SEB Exam Configuration
|
sebserver.exam.configuration.list.actions=
|
||||||
sebserver.exam.configuration.list.title=SEB Exam Configuration
|
sebserver.exam.configuration.list.title=SEB Exam Configuration
|
||||||
sebserver.exam.configuration.list.column.name=Name
|
sebserver.exam.configuration.list.column.name=Name
|
||||||
sebserver.exam.configuration.list.column.description=Description
|
sebserver.exam.configuration.list.column.description=Description
|
||||||
|
@ -404,7 +404,7 @@ sebserver.exam.configuration.form.description=Description
|
||||||
sebserver.exam.configuration.form.status=Status
|
sebserver.exam.configuration.form.status=Status
|
||||||
sebserver.exam.configuration.form.encryptSecret.confirm=Confirm Password
|
sebserver.exam.configuration.form.encryptSecret.confirm=Confirm Password
|
||||||
|
|
||||||
sebserver.exam.indicator.list.actions=Indicator
|
sebserver.exam.indicator.list.actions=
|
||||||
sebserver.exam.indicator.list.title=Indicators
|
sebserver.exam.indicator.list.title=Indicators
|
||||||
sebserver.exam.indicator.list.column.type=Type
|
sebserver.exam.indicator.list.column.type=Type
|
||||||
sebserver.exam.indicator.list.column.name=Name
|
sebserver.exam.indicator.list.column.name=Name
|
||||||
|
@ -1011,6 +1011,7 @@ sebserver.examconfig.props.validation.WindowsSizeValidator=Invalid number
|
||||||
# SEB Exam Configuration Template
|
# SEB Exam Configuration Template
|
||||||
################################
|
################################
|
||||||
|
|
||||||
|
sebserver.configtemplate.action.list=Configuration Templates
|
||||||
sebserver.configtemplate.list.title=Configuration Templates
|
sebserver.configtemplate.list.title=Configuration Templates
|
||||||
sebserver.configtemplate.list.empty=There is currently no SEB-Exam configuration template available. Please create a new one
|
sebserver.configtemplate.list.empty=There is currently no SEB-Exam configuration template available. Please create a new one
|
||||||
sebserver.configtemplate.list.actions=
|
sebserver.configtemplate.list.actions=
|
||||||
|
|
Loading…
Reference in a new issue