SEBSERV-44 SEBSERV-45 Exam - SEB Configuration mapping implementation

This commit is contained in:
anhefti 2019-05-27 16:29:09 +02:00
parent 5572e1ba9e
commit ba07076a88
36 changed files with 1011 additions and 111 deletions

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gbl.model.sebconfig;
package ch.ethz.seb.sebserver.gbl.model.exam;
import javax.validation.constraints.NotNull;
@ -16,9 +16,12 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Domain.CONFIGURATION_NODE;
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM_CONFIGURATION_MAP;
import ch.ethz.seb.sebserver.gbl.model.Domain.SEB_CLIENT_CONFIGURATION;
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
@JsonIgnoreProperties(ignoreUnknown = true)
public final class ExamConfigurationMap implements GrantEntity {
@ -35,14 +38,23 @@ public final class ExamConfigurationMap implements GrantEntity {
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_INSTITUTION_ID)
public final Long institutionId;
@NotNull
@NotNull(message = "examConfigurationMap:examId:notNull")
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_EXAM_ID)
public final Long examId;
@NotNull
@NotNull(message = "examConfigurationMap:configurationNodeId:notNull")
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID)
public final Long configurationNodeId;
@JsonProperty(CONFIGURATION_NODE.ATTR_NAME)
public final String configName;
@JsonProperty(CONFIGURATION_NODE.ATTR_DESCRIPTION)
public final String configDescription;
@JsonProperty(CONFIGURATION_NODE.ATTR_STATUS)
public final ConfigurationStatus configStatus;
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_USER_NAMES)
public final String userNames;
@ -59,8 +71,12 @@ public final class ExamConfigurationMap implements GrantEntity {
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_EXAM_ID) final Long examId,
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID) final Long configurationNodeId,
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_USER_NAMES) final String userNames,
@JsonProperty(SEB_CLIENT_CONFIGURATION.ATTR_ENCRYPT_SECRET) final CharSequence encryptSecret,
@JsonProperty(ATTR_CONFIRM_ENCRYPT_SECRET) final CharSequence confirmEncryptSecret) {
@JsonProperty(EXAM_CONFIGURATION_MAP.ATTR_ENCRYPT_SECRET) final CharSequence encryptSecret,
@JsonProperty(ATTR_CONFIRM_ENCRYPT_SECRET) final CharSequence confirmEncryptSecret,
@JsonProperty(CONFIGURATION_NODE.ATTR_NAME) final String configName,
@JsonProperty(CONFIGURATION_NODE.ATTR_DESCRIPTION) final String configDescription,
@JsonProperty(CONFIGURATION_NODE.ATTR_STATUS) final ConfigurationStatus configStatus) {
this.id = id;
this.institutionId = institutionId;
@ -69,6 +85,24 @@ public final class ExamConfigurationMap implements GrantEntity {
this.userNames = userNames;
this.encryptSecret = encryptSecret;
this.confirmEncryptSecret = confirmEncryptSecret;
this.configName = configName;
this.configDescription = configDescription;
this.configStatus = configStatus;
}
public ExamConfigurationMap(final Long institutionId, final POSTMapper postParams) {
this.id = null;
this.institutionId = institutionId;
this.examId = postParams.getLong(Domain.EXAM_CONFIGURATION_MAP.ATTR_EXAM_ID);
this.configurationNodeId = postParams.getLong(Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID);
this.userNames = postParams.getString(Domain.EXAM_CONFIGURATION_MAP.ATTR_USER_NAMES);
this.encryptSecret = postParams.getCharSequence(Domain.EXAM_CONFIGURATION_MAP.ATTR_ENCRYPT_SECRET);
this.confirmEncryptSecret = postParams.getCharSequence(ATTR_CONFIRM_ENCRYPT_SECRET);
this.configName = postParams.getString(Domain.CONFIGURATION_NODE.ATTR_NAME);
this.configDescription = postParams.getString(Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION);
this.configStatus = postParams.getEnum(Domain.CONFIGURATION_NODE.ATTR_STATUS, ConfigurationStatus.class);
}
@Override
@ -122,6 +156,18 @@ public final class ExamConfigurationMap implements GrantEntity {
return this.encryptSecret != null && this.encryptSecret.length() > 0;
}
public String getConfigName() {
return this.configName;
}
public String getConfigDescription() {
return this.configDescription;
}
public ConfigurationStatus getConfigStatus() {
return this.configStatus;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
@ -133,10 +179,20 @@ public final class ExamConfigurationMap implements GrantEntity {
builder.append(this.examId);
builder.append(", configurationNodeId=");
builder.append(this.configurationNodeId);
builder.append(", configName=");
builder.append(this.configName);
builder.append(", configDescription=");
builder.append(this.configDescription);
builder.append(", configStatus=");
builder.append(this.configStatus);
builder.append(", userNames=");
builder.append(this.userNames);
builder.append("]");
return builder.toString();
}
public static ExamConfigurationMap createNew(final Exam exam) {
return new ExamConfigurationMap(null, exam.institutionId, exam.id, null, null, null, null, null, null, null);
}
}

View file

@ -29,7 +29,7 @@ import ch.ethz.seb.sebserver.gbl.util.Utils;
@JsonIgnoreProperties(ignoreUnknown = true)
public final class Indicator implements Entity {
public static final String FILTER_ATTR_EXAM = "exam";
public static final String FILTER_ATTR_EXAM_ID = "examId";
public enum IndicatorType {
LAST_PING,

View file

@ -8,6 +8,9 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.function.BooleanSupplier;
import org.apache.commons.lang3.BooleanUtils;
@ -23,6 +26,7 @@ import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamStatus;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
@ -42,8 +46,10 @@ import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
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.exam.DeleteExamConfigMapping;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.DeleteIndicator;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingsPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicators;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizData;
@ -62,28 +68,50 @@ public class ExamForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(ExamForm.class);
private static final LocTextKey FORM_SUPPORTER_TEXT_KEY = new LocTextKey("sebserver.exam.form.supporter");
private static final LocTextKey FORM_STATUS_TEXT_KEY = new LocTextKey("sebserver.exam.form.status");
private static final LocTextKey FORM_TYPE_TEXT_KEY = new LocTextKey("sebserver.exam.form.type");
private static final LocTextKey FORM_ENDTIME_TEXT_KEY = new LocTextKey("sebserver.exam.form.endtime");
private static final LocTextKey FORM_STARTTIME_TEXT_KEY = new LocTextKey("sebserver.exam.form.starttime");
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY = new LocTextKey("sebserver.exam.form.description");
private static final LocTextKey FORM_NAME_TEXT_KEY = new LocTextKey("sebserver.exam.form.name");
private static final LocTextKey FORM_QUIZID_TEXT_KEY = new LocTextKey("sebserver.exam.form.quizid");
private static final LocTextKey FORM_LMSSETUP_TEXT_KEY = new LocTextKey("sebserver.exam.form.lmssetup");
private final PageService pageService;
private final ResourceService resourceService;
private final static LocTextKey listTitleKey =
private static final LocTextKey CONFIG_EMPTY_LIST_MESSAGE =
new LocTextKey("sebserver.exam.configuration.list.empty");
private static final LocTextKey INDICATOR_EMPTY_LIST_MESSAGE =
new LocTextKey("sebserver.exam.indicator.list.empty");
private static final LocTextKey FORM_SUPPORTER_TEXT_KEY =
new LocTextKey("sebserver.exam.form.supporter");
private static final LocTextKey FORM_STATUS_TEXT_KEY =
new LocTextKey("sebserver.exam.form.status");
private static final LocTextKey FORM_TYPE_TEXT_KEY =
new LocTextKey("sebserver.exam.form.type");
private static final LocTextKey FORM_ENDTIME_TEXT_KEY =
new LocTextKey("sebserver.exam.form.endtime");
private static final LocTextKey FORM_STARTTIME_TEXT_KEY =
new LocTextKey("sebserver.exam.form.starttime");
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.exam.form.description");
private static final LocTextKey FORM_NAME_TEXT_KEY =
new LocTextKey("sebserver.exam.form.name");
private static final LocTextKey FORM_QUIZID_TEXT_KEY =
new LocTextKey("sebserver.exam.form.quizid");
private static final LocTextKey FORM_LMSSETUP_TEXT_KEY =
new LocTextKey("sebserver.exam.form.lmssetup");
private final static LocTextKey CONFIG_LIST_TITLE_KEY =
new LocTextKey("sebserver.exam.configuration.list.title");
private final static LocTextKey CONFIG_NAME_COLUMN_KEY =
new LocTextKey("sebserver.exam.configuration.list.column.name");
private final static LocTextKey CONFIG_DESCRIPTION_COLUMN_KEY =
new LocTextKey("sebserver.exam.configuration.list.column.description");
private final static LocTextKey CONFIG_STATUS_COLUMN_KEY =
new LocTextKey("sebserver.exam.configuration.list.column.status");
private final static LocTextKey INDICATOR_LIST_TITLE_KEY =
new LocTextKey("sebserver.exam.indicator.list.title");
private final static LocTextKey typeColumnKey =
private final static LocTextKey INDICATOR_TYPE_COLUMN_KEY =
new LocTextKey("sebserver.exam.indicator.list.column.type");
private final static LocTextKey nameColumnKey =
private final static LocTextKey INDICATOR_NAME_COLUMN_KEY =
new LocTextKey("sebserver.exam.indicator.list.column.name");
private final static LocTextKey thresholdColumnKey =
private final static LocTextKey INDICATOR_THRESHOLD_COLUMN_KEY =
new LocTextKey("sebserver.exam.indicator.list.column.thresholds");
private final static LocTextKey emptySelectionTextKey =
private final static LocTextKey INDICATOR_EMPTY_SELECTION_TEXT_KEY =
new LocTextKey("sebserver.exam.indicator.list.pleaseSelect");
protected ExamForm(
@ -162,7 +190,6 @@ public class ExamForm implements TemplateComposer {
.putStaticValueIf(isNew,
QuizData.QUIZ_ATTR_ID,
exam.externalId)
.addField(FormBuilder.singleSelection(
Domain.EXAM.ATTR_LMS_SETUP_ID,
FORM_LMSSETUP_TEXT_KEY,
@ -237,35 +264,102 @@ public class ExamForm implements TemplateComposer {
.publishIf(() -> !readonly);
// additional data in read-only view
if (readonly) {
if (readonly && !importFromQuizData) {
// List of SEB Configuration
widgetFactory.labelLocalized(
content,
CustomVariant.TEXT_H3,
CONFIG_LIST_TITLE_KEY);
final EntityTable<ExamConfigurationMap> configurationTable =
this.pageService.entityTableBuilder(restService.getRestCall(GetExamConfigMappingsPage.class))
.withRestCallAdapter(builder -> builder.withQueryParam(
ExamConfigurationMap.FILTER_ATTR_EXAM_ID,
entityKey.modelId))
.withEmptyMessage(CONFIG_EMPTY_LIST_MESSAGE)
.withPaging(1)
.hideNavigation()
.withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_NAME,
CONFIG_NAME_COLUMN_KEY,
ExamConfigurationMap::getConfigName,
false))
.withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
CONFIG_DESCRIPTION_COLUMN_KEY,
ExamConfigurationMap::getConfigDescription,
false))
.withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_STATUS,
CONFIG_STATUS_COLUMN_KEY,
this.resourceService::localizedExamConfigStatusName,
false))
.withDefaultActionIf(
() -> editable,
() -> actionBuilder
.newAction(ActionDefinition.EXAM_CONFIGURATION_MODIFY_FROM_LIST)
.create())
.compose(content);
final EntityKey configMapKey = (configurationTable.hasAnyContent())
? configurationTable.getFirstRowData().getEntityKey()
: null;
actionBuilder
.newAction(ActionDefinition.EXAM_CONFIGURATION_NEW)
.withParentEntityKey(entityKey)
.publishIf(() -> modifyGrant && editable && !configurationTable.hasAnyContent())
.newAction(ActionDefinition.EXAM_CONFIGURATION_MODIFY_FROM_LIST)
.withParentEntityKey(entityKey)
.withEntityKey(configMapKey)
.publishIf(() -> modifyGrant && editable && configurationTable.hasAnyContent())
.newAction(ActionDefinition.EXAM_CONFIGURATION_DELETE_FROM_LIST)
.withEntityKey(entityKey)
.withSelect(
() -> {
final ExamConfigurationMap firstRowData = configurationTable.getFirstRowData();
if (firstRowData == null) {
return Collections.emptySet();
} else {
return new HashSet<>(Arrays.asList(firstRowData.getEntityKey()));
}
},
this::deleteExamConfigMapping,
null)
.publishIf(() -> modifyGrant && configurationTable.hasAnyContent() && editable);
// List of Indicators
widgetFactory.labelLocalized(
content,
CustomVariant.TEXT_H3,
listTitleKey);
INDICATOR_LIST_TITLE_KEY);
final EntityTable<Indicator> indicatorTable =
this.pageService.entityTableBuilder(restService.getRestCall(GetIndicators.class))
.withRestCallAdapter(builder -> builder.withQueryParam(
Indicator.FILTER_ATTR_EXAM,
Indicator.FILTER_ATTR_EXAM_ID,
entityKey.modelId))
.withEmptyMessage(new LocTextKey("sebserver.exam.indicator.list.empty"))
.withEmptyMessage(INDICATOR_EMPTY_LIST_MESSAGE)
.withPaging(5)
.hideNavigation()
.withColumn(new ColumnDefinition<>(
Domain.INDICATOR.ATTR_NAME,
nameColumnKey,
INDICATOR_NAME_COLUMN_KEY,
Indicator::getName,
false))
.withColumn(new ColumnDefinition<>(
Domain.INDICATOR.ATTR_TYPE,
typeColumnKey,
INDICATOR_TYPE_COLUMN_KEY,
this::indicatorTypeName,
false))
.withColumn(new ColumnDefinition<>(
Domain.THRESHOLD.REFERENCE_NAME,
thresholdColumnKey,
INDICATOR_THRESHOLD_COLUMN_KEY,
ExamForm::thresholdsValue,
false))
.withDefaultActionIf(
@ -285,18 +379,20 @@ public class ExamForm implements TemplateComposer {
.newAction(ActionDefinition.EXAM_INDICATOR_MODIFY_FROM_LIST)
.withParentEntityKey(entityKey)
.withSelect(indicatorTable::getSelection, PageAction::applySingleSelection, emptySelectionTextKey)
.withSelect(
indicatorTable::getSelection,
PageAction::applySingleSelection,
INDICATOR_EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> modifyGrant && indicatorTable.hasAnyContent() && editable)
.newAction(ActionDefinition.EXAM_INDICATOR_DELETE_FROM_LIST)
.withEntityKey(entityKey)
.withSelect(indicatorTable::getSelection, this::deleteSelectedIndicator, emptySelectionTextKey)
.withSelect(
indicatorTable::getSelection,
this::deleteSelectedIndicator,
INDICATOR_EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> modifyGrant && indicatorTable.hasAnyContent() && editable);
// TODO List of attached SEB Configurations
}
}
private PageAction deleteSelectedIndicator(final PageAction action) {
@ -308,6 +404,15 @@ public class ExamForm implements TemplateComposer {
return action;
}
private PageAction deleteExamConfigMapping(final PageAction action) {
final EntityKey examConfigMappingKey = action.getSingleSelection();
this.resourceService.getRestService()
.getBuilder(DeleteExamConfigMapping.class)
.withURIVariable(API.PARAM_MODEL_ID, examConfigMappingKey.modelId)
.call();
return action;
}
private Result<Exam> getExistingExam(final EntityKey entityKey, final RestService restService) {
return restService.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)

View file

@ -0,0 +1,212 @@
/*
* Copyright (c) 2019 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.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.Form;
import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle;
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.TemplateComposer;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMapping;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.NewExamConfigMapping;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExamConfigMapping;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@Lazy
@Component
@GuiProfile
public class ExamSebConfigMapForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(ExamSebConfigMapForm.class);
private static final LocTextKey NEW_CONFIG_MAPPING_TILE_TEXT_KEY =
new LocTextKey("sebserver.exam.configuration.form.title.new");
private static final LocTextKey CONFIG_MAPPING_TILE_TEXT_KEY =
new LocTextKey("sebserver.exam.configuration.form.title");
private static final LocTextKey CONFIG_MAPPING_NAME_TEXT_KEY =
new LocTextKey("sebserver.exam.configuration.form.name");
private static final LocTextKey FORM_DESCRIPTION_TEXT_KEY =
new LocTextKey("sebserver.exam.configuration.form.description");
private static final LocTextKey FORM_STATUS_TEXT_KEY =
new LocTextKey("sebserver.exam.configuration.form.status");
private static final LocTextKey FORM_ENCRYPT_SECRET_TEXT_KEY =
new LocTextKey("sebserver.exam.configuration.form.encryptSecret");
private static final LocTextKey FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY =
new LocTextKey("sebserver.exam.configuration.form.encryptSecret.confirm");
private final PageService pageService;
private final ResourceService resourceService;
protected ExamSebConfigMapForm(
final PageService pageService,
final ResourceService resourceService) {
this.pageService = pageService;
this.resourceService = resourceService;
}
@Override
public void compose(final PageContext pageContext) {
final RestService restService = this.resourceService.getRestService();
final WidgetFactory widgetFactory = this.pageService.getWidgetFactory();
final EntityKey entityKey = pageContext.getEntityKey();
final EntityKey parentEntityKey = pageContext.getParentEntityKey();
final boolean isNew = entityKey == null;
final boolean isReadonly = pageContext.isReadonly();
final Exam exam = (isNew)
? restService
.getBuilder(GetExam.class)
.withURIVariable(API.PARAM_MODEL_ID, parentEntityKey.modelId)
.call()
.get(pageContext::notifyError)
: null;
// get data or create new. Handle error if happen
final ExamConfigurationMap examConfigurationMap = (isNew)
? ExamConfigurationMap.createNew(exam)
: restService
.getBuilder(GetExamConfigMapping.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
.call()
.get(pageContext::notifyError);
if (examConfigurationMap == null) {
log.error("Failed to get ExamConfigurationMap. "
+ "Error is notified to the User. "
+ "See previous logs for more infomation");
return;
}
// new PageContext with actual EntityKey
final PageContext formContext = pageContext.withEntityKey(examConfigurationMap.getEntityKey());
// the default page layout
final LocTextKey titleKey = (isNew)
? NEW_CONFIG_MAPPING_TILE_TEXT_KEY
: CONFIG_MAPPING_TILE_TEXT_KEY;
final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(),
titleKey);
final FormHandle<ExamConfigurationMap> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.EXAM_CONFIGURATION_MAP.ATTR_ID,
examConfigurationMap.getModelId())
.putStaticValue(
Domain.EXAM_CONFIGURATION_MAP.ATTR_INSTITUTION_ID,
String.valueOf(examConfigurationMap.getInstitutionId()))
.putStaticValue(
Domain.EXAM_CONFIGURATION_MAP.ATTR_EXAM_ID,
String.valueOf(examConfigurationMap.examId))
.addField(FormBuilder.singleSelection(
Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID,
CONFIG_MAPPING_NAME_TEXT_KEY,
String.valueOf(examConfigurationMap.configurationNodeId),
this.resourceService::examConfigurationSelectionResources)
.withSelectionListener(this::updateFormValuesFromConfigSelection))
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_DESCRIPTION_TEXT_KEY,
examConfigurationMap.configDescription)
.asArea()
.readonly(true))
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_STATUS,
FORM_STATUS_TEXT_KEY,
this.resourceService.localizedExamConfigStatusName(examConfigurationMap))
.readonly(true))
.addField(FormBuilder.text(
Domain.EXAM_CONFIGURATION_MAP.ATTR_ENCRYPT_SECRET,
FORM_ENCRYPT_SECRET_TEXT_KEY)
.asPasswordField())
.addField(FormBuilder.text(
ExamConfigurationMap.ATTR_CONFIRM_ENCRYPT_SECRET,
FORM_CONFIRM_ENCRYPT_SECRET_TEXT_KEY)
.asPasswordField())
.buildFor((isNew)
? restService.getRestCall(NewExamConfigMapping.class)
: restService.getRestCall(SaveExamConfigMapping.class));
// propagate content actions to action-pane
this.pageService.pageActionBuilder(formContext.clearEntityKeys())
.newAction(ActionDefinition.EXAM_CONFIGURATION_SAVE)
.withEntityKey(parentEntityKey)
.withExec(formHandle::processFormSave)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly)
.newAction(ActionDefinition.EXAM_CONFIGURATION_CANCEL_MODIFY)
.withEntityKey(parentEntityKey)
.withExec(action -> this.pageService.onEmptyEntityKeyGoTo(
action,
ActionDefinition.EXAM_VIEW_LIST))
.publishIf(() -> !isReadonly);
}
private void updateFormValuesFromConfigSelection(final Form form) {
final String configId = form.getFieldValue(Domain.EXAM_CONFIGURATION_MAP.ATTR_CONFIGURATION_NODE_ID);
if (StringUtils.isBlank(configId)) {
form.setFieldValue(Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, null);
form.setFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS, null);
} else {
try {
final ConfigurationNode configuration = this.resourceService
.getRestService()
.getBuilder(GetExamConfigNode.class)
.withURIVariable(API.PARAM_MODEL_ID, configId)
.call()
.getOrThrow();
form.setFieldValue(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
configuration.description);
form.setFieldValue(
Domain.CONFIGURATION_NODE.ATTR_STATUS,
this.resourceService.localizedExamConfigStatusName(configuration));
} catch (final Exception e) {
log.error("Failed to update form values from SEB Configuration selection", e);
form.setFieldValue(Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION, null);
form.setFieldValue(Domain.CONFIGURATION_NODE.ATTR_STATUS, null);
}
}
}
}

View file

@ -43,6 +43,10 @@ public class IndicatorForm implements TemplateComposer {
private static final Logger log = LoggerFactory.getLogger(IndicatorForm.class);
private static final LocTextKey NEW_INDICATOR_TILE_TEXT_KEY =
new LocTextKey("sebserver.exam.indicator.form.title.new");
private static final LocTextKey INDICATOR_TILE_TEXT_KEY =
new LocTextKey("sebserver.exam.indicator.form.title");
private static final LocTextKey FORM_THRESHOLDS_TEXT_KEY =
new LocTextKey("sebserver.exam.indicator.form.thresholds");
private static final LocTextKey FORM_COLOR_TEXT_KEY =
@ -100,10 +104,9 @@ public class IndicatorForm implements TemplateComposer {
final PageContext formContext = pageContext.withEntityKey(indicator.getEntityKey());
// the default page layout
final LocTextKey titleKey = new LocTextKey(
(isNew)
? "sebserver.exam.indicator.form.title.new"
: "sebserver.exam.indicator.form.title");
final LocTextKey titleKey = (isNew)
? NEW_INDICATOR_TILE_TEXT_KEY
: INDICATOR_TILE_TEXT_KEY;
final Composite content = widgetFactory.defaultPageLayout(
formContext.getParent(),
titleKey);

View file

@ -8,14 +8,11 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.function.Function;
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.Constants;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.Entity;
@ -114,7 +111,7 @@ public class SebExamConfigList implements TemplateComposer {
() -> new ColumnDefinition<>(
Domain.LMS_SETUP.ATTR_INSTITUTION_ID,
INSTITUTION_TEXT_KEY,
examConfigInstitutionNameFunction(this.resourceService),
this.resourceService::localizedExamConfigInstitutionName,
this.institutionFilter,
false))
.withColumn(new ColumnDefinition<>(
@ -132,7 +129,7 @@ public class SebExamConfigList implements TemplateComposer {
.withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_NODE.ATTR_STATUS,
STATUS_TEXT_KEY,
this::examConfigStatusName,
this.resourceService::localizedExamConfigStatusName,
this.statusFilter,
true))
.withDefaultAction(pageActionBuilder
@ -141,7 +138,6 @@ public class SebExamConfigList implements TemplateComposer {
.compose(content);
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_NEW)
@ -160,20 +156,4 @@ public class SebExamConfigList implements TemplateComposer {
.publishIf(() -> examConfigGrant.im() && table.hasAnyContent());
}
private static Function<ConfigurationNode, String> examConfigInstitutionNameFunction(
final ResourceService resourceService) {
return config -> resourceService.getInstitutionNameFunction()
.apply(String.valueOf(config.institutionId));
}
private String examConfigStatusName(final ConfigurationNode config) {
if (config.status == null) {
return Constants.EMPTY_NOTE;
}
return this.resourceService.getI18nSupport()
.getText(ResourceService.EXAMCONFIG_STATUS_PREFIX + config.status.name());
}
}

View file

@ -134,7 +134,8 @@ public class SebExamConfigPropForm implements TemplateComposer {
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_DESCRIPTION_TEXT_KEY,
examConfig.description).asArea())
examConfig.description)
.asArea())
.addField(FormBuilder.singleSelection(
Domain.CONFIGURATION_NODE.ATTR_STATUS,
FORM_STATUS_TEXT_KEY,

View file

@ -17,7 +17,8 @@ public enum ActionCategory {
LMS_SETUP_LIST(new LocTextKey("sebserver.lmssetup.list.actions"), 1),
QUIZ_LIST(new LocTextKey("sebserver.quizdiscovery.list.actions"), 1),
EXAM_LIST(new LocTextKey("sebserver.exam.list.actions"), 1),
INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 1),
EXAM_CONFIG_MAPPING_LIST(new LocTextKey("sebserver.exam.configuration.list.actions"), 1),
INDICATOR_LIST(new LocTextKey("sebserver.exam.indicator.list.actions"), 2),
SEB_CLIENT_CONFIG_LIST(new LocTextKey("sebserver.clientconfig.list.actions"), 1),
SEB_EXAM_CONFIG_LIST(new LocTextKey("sebserver.examconfig.list.actions"), 1),
VARIA(new LocTextKey("sebserver.overall.action.category.varia"), 100),

View file

@ -228,10 +228,37 @@ public enum ActionDefinition {
PageStateDefinition.EXAM_VIEW,
ActionCategory.FORM),
EXAM_CONFIGURATION_NEW(
new LocTextKey("sebserver.exam.configuration.action.list.new"),
ImageIcon.NEW,
PageStateDefinition.EXAM_CONFIG_MAP_EDIT,
ActionCategory.EXAM_CONFIG_MAPPING_LIST),
EXAM_CONFIGURATION_MODIFY_FROM_LIST(
new LocTextKey("sebserver.exam.configuration.action.list.modify"),
ImageIcon.EDIT,
PageStateDefinition.EXAM_CONFIG_MAP_EDIT,
ActionCategory.EXAM_CONFIG_MAPPING_LIST),
EXAM_CONFIGURATION_DELETE_FROM_LIST(
new LocTextKey("sebserver.exam.configuration.action.list.delete"),
ImageIcon.DELETE,
PageStateDefinition.EXAM_VIEW,
ActionCategory.EXAM_CONFIG_MAPPING_LIST),
EXAM_CONFIGURATION_SAVE(
new LocTextKey("sebserver.exam.configuration.action.save"),
ImageIcon.SAVE,
PageStateDefinition.EXAM_VIEW,
ActionCategory.FORM),
EXAM_CONFIGURATION_CANCEL_MODIFY(
new LocTextKey("sebserver.overall.action.modify.cancel"),
ImageIcon.CANCEL,
PageStateDefinition.EXAM_VIEW,
ActionCategory.FORM),
EXAM_INDICATOR_NEW(
new LocTextKey("sebserver.exam.indicator.action.list.new"),
ImageIcon.NEW,
PageStateDefinition.INDICATOR_EDIT),
PageStateDefinition.INDICATOR_EDIT,
ActionCategory.INDICATOR_LIST),
EXAM_INDICATOR_MODIFY_FROM_LIST(
new LocTextKey("sebserver.exam.indicator.action.list.modify"),
ImageIcon.EDIT,
@ -325,7 +352,7 @@ public enum ActionDefinition {
ActionCategory.FORM),
SEB_EXAM_CONFIG_MODIFY(
new LocTextKey("sebserver.examconfig.action.modify"),
ImageIcon.EDIT,
ImageIcon.EDIT_SETTINGS,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
ActionCategory.FORM),
SEB_EXAM_CONFIG_CANCEL_MODIFY(
@ -341,7 +368,7 @@ public enum ActionDefinition {
SEB_EXAM_CONFIG_MODIFY_FROM_LIST(
new LocTextKey("sebserver.examconfig.action.list.modify"),
ImageIcon.EDIT,
ImageIcon.EDIT_SETTINGS,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
ActionCategory.SEB_EXAM_CONFIG_LIST),
@ -352,7 +379,7 @@ public enum ActionDefinition {
ActionCategory.SEB_EXAM_CONFIG_LIST),
SEB_EXAM_CONFIG_UNDO(
new LocTextKey("sebserver.examconfig.action.undo"),
ImageIcon.SAVE,
ImageIcon.UNDO,
PageStateDefinition.SEB_EXAM_CONFIG_EDIT,
ActionCategory.SEB_EXAM_CONFIG_LIST),

View file

@ -119,9 +119,9 @@ public class ActionPane implements TemplateComposer {
}
}
final Label labelSeparator = this.widgetFactory.labelSeparator(composite);
final GridData separatorLayout = new GridData(SWT.FILL, SWT.TOP, true, false);
labelSeparator.setLayoutData(separatorLayout);
// final Label labelSeparator = this.widgetFactory.labelSeparator(composite);
// final GridData separatorLayout = new GridData(SWT.FILL, SWT.TOP, true, false);
// labelSeparator.setLayoutData(separatorLayout);
// title
if (category.title != null) {
@ -140,7 +140,7 @@ public class ActionPane implements TemplateComposer {
composite,
SWT.SINGLE | SWT.FULL_SELECTION);
actions.setData(RWT.CUSTOM_VARIANT, "actions");
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
actions.setLayoutData(gridData);
final Template template = new Template();
final ImageCell imageCell = new ImageCell(template);

View file

@ -10,6 +10,7 @@ package ch.ethz.seb.sebserver.gui.content.activity;
import ch.ethz.seb.sebserver.gui.content.ExamForm;
import ch.ethz.seb.sebserver.gui.content.ExamList;
import ch.ethz.seb.sebserver.gui.content.ExamSebConfigMapForm;
import ch.ethz.seb.sebserver.gui.content.IndicatorForm;
import ch.ethz.seb.sebserver.gui.content.InstitutionForm;
import ch.ethz.seb.sebserver.gui.content.InstitutionList;
@ -49,6 +50,7 @@ public enum PageStateDefinition implements PageState {
EXAM_LIST(Type.LIST_VIEW, ExamList.class, ActivityDefinition.EXAM),
EXAM_VIEW(Type.FORM_VIEW, ExamForm.class, ActivityDefinition.EXAM),
EXAM_EDIT(Type.FORM_EDIT, ExamForm.class, ActivityDefinition.EXAM),
EXAM_CONFIG_MAP_EDIT(Type.FORM_EDIT, ExamSebConfigMapForm.class, ActivityDefinition.EXAM),
INDICATOR_EDIT(Type.FORM_EDIT, IndicatorForm.class, ActivityDefinition.EXAM),
SEB_CLIENT_CONFIG_LIST(Type.LIST_VIEW, SebClientConfigList.class, ActivityDefinition.SEB_CLIENT_CONFIG),

View file

@ -143,6 +143,24 @@ public final class Form implements FormBinding {
this.formFields.add(name, createAccessor(label, imageUpload));
}
public String getFieldValue(final String attributeName) {
final FormFieldAccessor fieldAccessor = this.formFields.getFirst(attributeName);
if (fieldAccessor == null) {
return null;
}
return fieldAccessor.getStringValue();
}
public void setFieldValue(final String attributeName, final String attributeValue) {
final FormFieldAccessor fieldAccessor = this.formFields.getFirst(attributeName);
if (fieldAccessor == null) {
return;
}
fieldAccessor.setStringValue(attributeValue);
}
public void allVisible() {
process(
name -> true,
@ -208,11 +226,13 @@ public final class Form implements FormBinding {
private FormFieldAccessor createAccessor(final Label label, final Label field) {
return new FormFieldAccessor(label, field) {
@Override public String getStringValue() { return null; }
@Override public void setStringValue(final String value) { field.setText( (value == null) ? StringUtils.EMPTY : value); }
};
}
private FormFieldAccessor createAccessor(final Label label, final Text text) {
return new FormFieldAccessor(label, text) {
@Override public String getStringValue() { return text.getText(); }
@Override public void setStringValue(final String value) { text.setText( (value == null) ? StringUtils.EMPTY : value); }
};
}
private FormFieldAccessor createAccessor(final Label label, final Selection selection) {
@ -234,6 +254,7 @@ public final class Form implements FormBinding {
jsonValueAdapter,
selection.type() != Type.SINGLE) {
@Override public String getStringValue() { return selection.getSelectionValue(); }
@Override public void setStringValue(final String value) { selection.select(value); }
};
}
private FormFieldAccessor createAccessor(final Label label, final ThresholdList thresholdList) {
@ -356,6 +377,10 @@ public final class Form implements FormBinding {
public abstract String getStringValue();
public void setStringValue(final String value) {
throw new UnsupportedOperationException();
}
public void setVisible(final boolean visible) {
this.label.setVisible(visible);
this.control.setVisible(visible);

View file

@ -256,7 +256,7 @@ public class FormBuilder {
Label valueLabel(final Composite parent, final String value, final int hspan) {
final Label label = new Label(parent, SWT.NONE);
label.setText((StringUtils.isNoneBlank(value)) ? value : Constants.EMPTY_NOTE);
final GridData gridData = new GridData(SWT.LEFT, SWT.CENTER, true, false, hspan, 1);
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false, hspan, 1);
gridData.verticalIndent = 4;
label.setLayoutData(gridData);
return label;

View file

@ -24,17 +24,23 @@ import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam.ExamType;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator.IndicatorType;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.LmsType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Tuple;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfigMappingNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetupNames;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.useraccount.GetUserAccountNames;
@ -105,6 +111,28 @@ public class ResourceService {
.collect(Collectors.toList());
}
public List<Tuple<String>> examConfigurationSelectionResources() {
return getExamConfigurationSelection()
.getOr(Collections.emptyList())
.stream()
.map(entityName -> new Tuple<>(entityName.modelId, entityName.name))
.collect(Collectors.toList());
}
// public Function<String, String> getExamConfigurationNameFunction() {
// final Map<String, String> idNameMap = getExamConfigurationSelection()
// .getOr(Collections.emptyList())
// .stream()
// .collect(Collectors.toMap(e -> e.modelId, e -> e.name));
//
// return id -> {
// if (!idNameMap.containsKey(id)) {
// return Constants.EMPTY_NOTE;
// }
// return idNameMap.get(id);
// };
// }
public List<Tuple<String>> userRoleResources() {
return UserRole.publicRolesForUser(this.currentUser.get())
.stream()
@ -125,7 +153,6 @@ public class ResourceService {
}
public Function<String, String> getInstitutionNameFunction() {
final Map<String, String> idNameMap = this.restService.getBuilder(GetInstitutionNames.class)
.withQueryParam(Entity.FILTER_ATTR_ACTIVE, Constants.TRUE_STRING)
.call()
@ -248,4 +275,41 @@ public class ResourceService {
: this.i18nSupport.getText(INACTIVE_TEXT_KEY);
}
public String localizedExamConfigInstitutionName(final ConfigurationNode config) {
return getInstitutionNameFunction()
.apply(String.valueOf(config.institutionId));
}
public String localizedExamConfigStatusName(final ConfigurationNode config) {
if (config.status == null) {
return Constants.EMPTY_NOTE;
}
return this.i18nSupport
.getText(ResourceService.EXAMCONFIG_STATUS_PREFIX + config.status.name());
}
public String localizedExamConfigStatusName(final ExamConfigurationMap config) {
if (config.configStatus == null) {
return Constants.EMPTY_NOTE;
}
return this.i18nSupport
.getText(ResourceService.EXAMCONFIG_STATUS_PREFIX + config.configStatus.name());
}
private Result<List<EntityName>> getExamConfigurationSelection() {
return this.restService.getBuilder(GetExamConfigMappingNames.class)
.withQueryParam(
Entity.FILTER_ATTR_INSTITUTION,
String.valueOf(this.currentUser.get().institutionId))
.withQueryParam(
ConfigurationNode.FILTER_ATTR_TYPE,
ConfigurationType.EXAM_CONFIG.name())
.withQueryParam(
ConfigurationNode.FILTER_ATTR_STATUS,
ConfigurationStatus.READY_TO_USE.name())
.call();
}
}

View file

@ -298,8 +298,8 @@ public class TableFieldBuilder implements InputFieldBuilder {
item.setImage(
cellIndex,
(BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null))
? ImageIcon.ACTIVE.getImage(this.control.getDisplay())
: ImageIcon.INACTIVE.getImage(this.control.getDisplay()));
? ImageIcon.YES.getImage(this.control.getDisplay())
: ImageIcon.NO.getImage(this.control.getDisplay()));
} else {
item.setText(
cellIndex,

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2019 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.service.remote.webservice.api.exam;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class DeleteExamConfigMapping extends RestCall<EntityProcessingReport> {
protected DeleteExamConfigMapping() {
super(new TypeKey<>(
CallType.DELETE,
EntityType.EXAM_CONFIGURATION_MAP,
new TypeReference<EntityProcessingReport>() {
}),
HttpMethod.DELETE,
MediaType.APPLICATION_JSON_UTF8,
API.EXAM_CONFIGURATION_MAP_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2019 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.service.remote.webservice.api.exam;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class GetExamConfigMapping extends RestCall<ExamConfigurationMap> {
protected GetExamConfigMapping() {
super(new TypeKey<>(
CallType.GET_SINGLE,
EntityType.EXAM_CONFIGURATION_MAP,
new TypeReference<ExamConfigurationMap>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.EXAM_CONFIGURATION_MAP_ENDPOINT + API.MODEL_ID_VAR_PATH_SEGMENT);
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2019 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.service.remote.webservice.api.exam;
import java.util.List;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class GetExamConfigMappingNames extends RestCall<List<EntityName>> {
protected GetExamConfigMappingNames() {
super(new TypeKey<>(
CallType.GET_NAMES,
EntityType.CONFIGURATION_NODE,
new TypeReference<List<EntityName>>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.CONFIGURATION_NODE_ENDPOINT + API.NAMES_PATH_SEGMENT);
}
}

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2019 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.service.remote.webservice.api.exam;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Page;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class GetExamConfigMappingsPage extends RestCall<Page<ExamConfigurationMap>> {
protected GetExamConfigMappingsPage() {
super(new TypeKey<>(
CallType.GET_PAGE,
EntityType.EXAM_CONFIGURATION_MAP,
new TypeReference<Page<ExamConfigurationMap>>() {
}),
HttpMethod.GET,
MediaType.APPLICATION_FORM_URLENCODED,
API.EXAM_CONFIGURATION_MAP_ENDPOINT);
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2019 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.service.remote.webservice.api.exam;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class NewExamConfigMapping extends RestCall<ExamConfigurationMap> {
protected NewExamConfigMapping() {
super(new TypeKey<>(
CallType.NEW,
EntityType.EXAM_CONFIGURATION_MAP,
new TypeReference<ExamConfigurationMap>() {
}),
HttpMethod.POST,
MediaType.APPLICATION_FORM_URLENCODED,
API.EXAM_CONFIGURATION_MAP_ENDPOINT);
}
}

View file

@ -0,0 +1,40 @@
/*
* Copyright (c) 2019 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.service.remote.webservice.api.exam;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.core.type.TypeReference;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
@Lazy
@Component
@GuiProfile
public class SaveExamConfigMapping extends RestCall<ExamConfigurationMap> {
protected SaveExamConfigMapping() {
super(new TypeKey<>(
CallType.SAVE,
EntityType.EXAM_CONFIGURATION_MAP,
new TypeReference<ExamConfigurationMap>() {
}),
HttpMethod.PUT,
MediaType.APPLICATION_JSON_UTF8,
API.EXAM_CONFIGURATION_MAP_ENDPOINT);
}
}

View file

@ -101,7 +101,6 @@ public class EntityTable<ROW extends Entity> {
layout.verticalSpacing = 0;
this.composite.setLayout(layout);
GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
// gridData.heightHint = (pageSize + 2) * 40;
this.composite.setLayoutData(gridData);
// TODO just for debugging, remove when tested
@ -223,6 +222,19 @@ public class EntityTable<ROW extends Entity> {
return getRowDataId(selection[0]);
}
public ROW getFirstRowData() {
if (!this.hasAnyContent()) {
return null;
}
final TableItem item = this.table.getItem(0);
if (item == null) {
return null;
}
return getRowData(item);
}
public ROW getSelectedROWData() {
final TableItem[] selection = this.table.getSelection();
if (selection == null || selection.length == 0) {
@ -296,9 +308,6 @@ public class EntityTable<ROW extends Entity> {
// TODO error handling
});
final GridData gridData = (GridData) this.composite.getLayoutData();
gridData.heightHint = (this.table.getItemCount() + 2) * 50;
this.composite.layout(true, true);
}
@ -405,9 +414,9 @@ public class EntityTable<ROW extends Entity> {
private static void addBooleanCell(final TableItem item, final int index, final Object value) {
if ((Boolean) value) {
item.setImage(index, ImageIcon.ACTIVE.getImage(item.getDisplay()));
item.setImage(index, ImageIcon.YES.getImage(item.getDisplay()));
} else {
item.setImage(index, ImageIcon.INACTIVE.getImage(item.getDisplay()));
item.setImage(index, ImageIcon.NO.getImage(item.getDisplay()));
}
}

View file

@ -0,0 +1,17 @@
/*
* Copyright (c) 2019 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.widget;
public class PopupListSelection {
public PopupListSelection() {
// TODO Auto-generated constructor stub
}
}

View file

@ -68,6 +68,7 @@ public class WidgetFactory {
ADD_BOX("add_box.png"),
REMOVE_BOX("remove_box.png"),
EDIT("edit.png"),
EDIT_SETTINGS("settings.png"),
TEST("test.png"),
IMPORT("import.png"),
CANCEL("cancel.png"),
@ -75,10 +76,13 @@ public class WidgetFactory {
SHOW("show.png"),
ACTIVE("active.png"),
INACTIVE("inactive.png"),
YES("yes.png"),
NO("no.png"),
SAVE("save.png"),
NEW("new.png"),
DELETE("delete.png"),
SEARCH("lens.png"),
UNDO("undo.png"),
COLOR("color.png");
private String fileName;

View file

@ -8,7 +8,7 @@
package ch.ethz.seb.sebserver.webservice.servicelayer.dao;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionSupportDAO;
public interface ExamConfigurationMapDAO extends

View file

@ -15,6 +15,7 @@ import org.springframework.util.MultiValueMap;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
@ -22,7 +23,6 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.util.Utils;
@ -100,7 +100,7 @@ public class FilterMap extends POSTMapper {
}
public Long getIndicatorExamId() {
return getLong(Indicator.FILTER_ATTR_EXAM);
return getLong(Indicator.FILTER_ATTR_EXAM_ID);
}
public String getIndicatorName() {

View file

@ -213,10 +213,10 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
data.id,
null,
null,
null,
data.name,
data.description,
null,
null,
(data.status != null) ? data.status.name() : ConfigurationStatus.CONSTRUCTION.name());
this.configurationNodeRecordMapper.updateByPrimaryKeySelective(newRecord);

View file

@ -19,6 +19,7 @@ import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.dynamic.sql.SqlBuilder;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@ -29,7 +30,8 @@ import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.ErrorMessage;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationStatus;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationNodeRecordMapper;
@ -79,7 +81,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
@Transactional(readOnly = true)
public Result<ExamConfigurationMap> byPK(final Long id) {
return recordById(id)
.flatMap(ExamConfigurationMapDAOImpl::toDomainModel);
.flatMap(this::toDomainModel);
}
@Override
@ -91,7 +93,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
.build()
.execute()
.stream()
.map(ExamConfigurationMapDAOImpl::toDomainModel)
.map(this::toDomainModel)
.flatMap(DAOLoggingSupport::logAndSkipOnError)
.collect(Collectors.toList());
});
@ -117,7 +119,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
.build()
.execute()
.stream()
.map(ExamConfigurationMapDAOImpl::toDomainModel)
.map(this::toDomainModel)
.flatMap(DAOLoggingSupport::logAndSkipOnError)
.filter(predicate)
.collect(Collectors.toList()));
@ -139,7 +141,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
this.examConfigurationMapRecordMapper.insert(newRecord);
return newRecord;
})
.flatMap(ExamConfigurationMapDAOImpl::toDomainModel)
.flatMap(this::toDomainModel)
.onError(TransactionHandler::rollback);
}
@ -159,7 +161,7 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
this.examConfigurationMapRecordMapper.updateByPrimaryKeySelective(newRecord);
return this.examConfigurationMapRecordMapper.selectByPrimaryKey(data.id);
})
.flatMap(ExamConfigurationMapDAOImpl::toDomainModel)
.flatMap(this::toDomainModel)
.onError(TransactionHandler::rollback);
}
@ -223,15 +225,25 @@ public class ExamConfigurationMapDAOImpl implements ExamConfigurationMapDAO {
});
}
private static Result<ExamConfigurationMap> toDomainModel(final ExamConfigurationMapRecord record) {
return Result.tryCatch(() -> new ExamConfigurationMap(
record.getId(),
record.getInstitutionId(),
record.getExamId(),
record.getConfigurationNodeId(),
record.getUserNames(),
null,
null));
private Result<ExamConfigurationMap> toDomainModel(final ExamConfigurationMapRecord record) {
return Result.tryCatch(() -> {
final ConfigurationNodeRecord selectByPrimaryKey = this.configurationNodeRecordMapper
.selectByPrimaryKey(record.getConfigurationNodeId());
final String status = selectByPrimaryKey.getStatus();
return new ExamConfigurationMap(
record.getId(),
record.getInstitutionId(),
record.getExamId(),
record.getConfigurationNodeId(),
record.getUserNames(),
null,
null,
selectByPrimaryKey.getName(),
selectByPrimaryKey.getDescription(),
(StringUtils.isNotBlank(status)) ? ConfigurationStatus.valueOf(status) : null);
});
}
private Result<ExamConfigurationMap> checkMappingIntegrity(final ExamConfigurationMap data) {

View file

@ -30,9 +30,9 @@ import org.springframework.web.bind.annotation.RequestParam;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.API.BulkActionType;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.api.authorization.PrivilegeType;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityName;

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2019 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.webservice.weblayer.api;
import org.mybatis.dynamic.sql.SqlTable;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.GrantEntity;
import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamConfigurationMapRecordDynamicSqlSupport;
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.EntityDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ExamDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
@WebServiceProfile
@RestController
@RequestMapping("/${sebserver.webservice.api.admin.endpoint}" + API.EXAM_CONFIGURATION_MAP_ENDPOINT)
public class ExamConfigurationMappingController extends EntityController<ExamConfigurationMap, ExamConfigurationMap> {
private final ExamDAO examDao;
protected ExamConfigurationMappingController(
final AuthorizationService authorization,
final BulkActionService bulkActionService,
final EntityDAO<ExamConfigurationMap, ExamConfigurationMap> entityDAO,
final UserActivityLogDAO userActivityLogDAO,
final PaginationService paginationService,
final BeanValidationService beanValidationService,
final ExamDAO examDao) {
super(
authorization,
bulkActionService,
entityDAO,
userActivityLogDAO,
paginationService,
beanValidationService);
this.examDao = examDao;
}
@Override
protected ExamConfigurationMap createNew(final POSTMapper postParams) {
final Long institutionId = postParams.getLong(API.PARAM_INSTITUTION_ID);
return new ExamConfigurationMap(institutionId, postParams);
}
@Override
protected SqlTable getSQLTableOfEntity() {
return ExamConfigurationMapRecordDynamicSqlSupport.examConfigurationMapRecord;
}
@Override
protected EntityType getGrantEntityType() {
return EntityType.EXAM;
}
@Override
protected GrantEntity toGrantEntity(final ExamConfigurationMap entity) {
if (entity == null) {
return null;
}
return this.examDao
.byPK(entity.examId)
.getOrThrow();
}
@Override
protected Result<ExamConfigurationMap> checkCreateAccess(final ExamConfigurationMap entity) {
final GrantEntity grantEntity = toGrantEntity(entity);
this.authorization.checkWrite(grantEntity);
return Result.of(entity);
}
@Override
protected Result<ExamConfigurationMap> validForCreate(final ExamConfigurationMap entity) {
return super.validForCreate(entity)
.map(this::checkPasswordMatch);
}
@Override
protected Result<ExamConfigurationMap> validForSave(final ExamConfigurationMap entity) {
return super.validForSave(entity)
.map(this::checkPasswordMatch);
}
private ExamConfigurationMap checkPasswordMatch(final ExamConfigurationMap entity) {
if (entity.hasEncryptionSecret() && !entity.encryptSecret.equals(entity.confirmEncryptSecret)) {
throw new APIMessageException(APIMessage.fieldValidationError(
new FieldError(
Domain.EXAM_CONFIGURATION_MAP.TYPE_NAME,
PasswordChange.ATTR_NAME_PASSWORD,
"examConfigMapping:confirm_encrypt_secret:password.mismatch")));
}
return entity;
}
}

View file

@ -272,7 +272,27 @@ sebserver.exam.status.UP_COMING=Up Coming
sebserver.exam.status.RUNNING=Running
sebserver.exam.status.FINISHED=Finished
sebserver.exam.indicator.list.actions=Selected Indicator
sebserver.exam.configuration.list.actions=SEB Configuration
sebserver.exam.configuration.list.title=SEB Configuration
sebserver.exam.configuration.list.column.name=Name
sebserver.exam.configuration.list.column.description=Description
sebserver.exam.configuration.list.column.status=Status
sebserver.exam.configuration.list.empty=There is currently no SEB Configuration defined for this Exam. Please add one
sebserver.exam.configuration.action.list.new=Add
sebserver.exam.configuration.action.list.modify=Edit
sebserver.exam.configuration.action.list.delete=Delete
sebserver.exam.configuration.action.save=Save
sebserver.exam.configuration.form.title.new=Add SEB Configuration Mapping
sebserver.exam.configuration.form.title=SEB Configuration Mapping
sebserver.exam.configuration.form.name=SEB Configuration
sebserver.exam.configuration.form.encryptSecret=Encryption Password
sebserver.exam.configuration.form.description=Description
sebserver.exam.configuration.form.status=Status
sebserver.exam.configuration.form.encryptSecret.confirm=Confirm Password
sebserver.exam.indicator.list.actions=Indicator
sebserver.exam.indicator.list.title=Indicators
sebserver.exam.indicator.list.column.type=Type
sebserver.exam.indicator.list.column.name=Name
@ -285,9 +305,9 @@ sebserver.exam.indicator.type.ERROR_COUNT=Error Count
sebserver.exam.indicator.info.pleaseSelect=Please Select an Indicator first
sebserver.exam.indicator.action.list.new=New Indicator
sebserver.exam.indicator.action.list.modify=Edit
sebserver.exam.indicator.action.list.delete=Delete
sebserver.exam.indicator.action.list.new=New
sebserver.exam.indicator.action.list.modify=Edit Selected
sebserver.exam.indicator.action.list.delete=Delete Selected
sebserver.exam.indicator.action.save=Save
sebserver.exam.indicator.form.title=Indicator

View file

@ -40,7 +40,6 @@ sebserver.error.unexpected=Unexpected Error
sebserver.page.message=Information
sebserver.dialog.confirm.title=Confirmation
sebserver.dialog.confirm.deactivation=Note that there are {0} other entities that belong to this entity.<br/>These will also be deactivated by deactivating this entity.<br/><br/>Are You sure you want to deactivate this entity?
sebserver.dialog.confirm.deactivation.noDependencies=Are You sure you want to deactivate?
################################
@ -266,7 +265,7 @@ sebserver.exam.type.MANAGED=Managed Devices
sebserver.exam.type.BYOD=Bring Your Own Device
sebserver.exam.type.VDI=VDI (Virtual Desktop Infrastructure)
sebserver.exam.indicator.list.actions=Selected Indicator
sebserver.exam.indicator.list.actions=Indicator
sebserver.exam.indicator.list.title=Indicators
sebserver.exam.indicator.list.column.type=Type
sebserver.exam.indicator.list.column.name=Name
@ -279,9 +278,9 @@ sebserver.exam.indicator.type.ERROR_COUNT=Error Count
sebserver.exam.indicator.info.pleaseSelect=Please select an indicator first
sebserver.exam.indicator.action.list.new=New Indicator
sebserver.exam.indicator.action.list.modify=Edit
sebserver.exam.indicator.action.list.delete=Delete
sebserver.exam.indicator.action.list.new=New
sebserver.exam.indicator.action.list.modify=Edit Selected
sebserver.exam.indicator.action.list.delete=Delete Selected
sebserver.exam.indicator.action.save=Save
sebserver.exam.indicator.form.title=Indicator

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B