SEBSERV-218 implemented

This commit is contained in:
anhefti 2022-06-16 10:56:42 +02:00
parent a979d4c13b
commit 3b4c168c43
7 changed files with 159 additions and 12 deletions

View file

@ -8,6 +8,10 @@
package ch.ethz.seb.sebserver.gui.content.configs; package ch.ethz.seb.sebserver.gui.content.configs;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
@ -19,13 +23,16 @@ import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.model.Domain; import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport; import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; 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.ConfigurationStatus;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute; import ch.ethz.seb.sebserver.gbl.model.sebconfig.TemplateAttribute;
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.gbl.util.Result;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition;
import ch.ethz.seb.sebserver.gui.form.FormBuilder; import ch.ethz.seb.sebserver.gui.form.FormBuilder;
import ch.ethz.seb.sebserver.gui.form.FormHandle; import ch.ethz.seb.sebserver.gui.form.FormHandle;
@ -40,6 +47,8 @@ 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.page.impl.PageAction;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.DeleteExamConfiguration; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.DeleteExamConfiguration;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurationValues;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetConfigurations;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetTemplateAttributePage; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetTemplateAttributePage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig; import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.NewExamConfig;
@ -75,6 +84,8 @@ public class ConfigTemplateForm implements TemplateComposer {
new LocTextKey("sebserver.configtemplate.attrs.list.view"); new LocTextKey("sebserver.configtemplate.attrs.list.view");
private static final LocTextKey ATTRIBUTES_LIST_GROUP_TEXT_KEY = private static final LocTextKey ATTRIBUTES_LIST_GROUP_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.group"); new LocTextKey("sebserver.configtemplate.attrs.list.group");
private static final LocTextKey ATTRIBUTES_LIST_VALUE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.value");
private static final LocTextKey ATTRIBUTES_LIST_TYPE_TEXT_KEY = private static final LocTextKey ATTRIBUTES_LIST_TYPE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.type"); new LocTextKey("sebserver.configtemplate.attrs.list.type");
private static final LocTextKey EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY = private static final LocTextKey EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY =
@ -205,6 +216,20 @@ public class ConfigTemplateForm implements TemplateComposer {
TemplateAttribute.FILTER_ATTR_TYPE, TemplateAttribute.FILTER_ATTR_TYPE,
this.resourceService::getAttributeTypeResources); this.resourceService::getAttributeTypeResources);
// TODO move this to an supplier that also can be updated
// the follow-up configuration
final Configuration configuration = this.restService
.getBuilder(GetConfigurations.class)
.withQueryParam(Configuration.FILTER_ATTR_CONFIGURATION_NODE_ID, examConfig.getModelId())
.withQueryParam(Configuration.FILTER_ATTR_FOLLOWUP, Constants.TRUE_STRING)
.call()
.map(Utils::toSingleton)
.onError(error -> pageContext.notifyLoadError(EntityType.CONFIGURATION, error))
.getOrThrow();
final AttributeValueSupplier attributeValueSupplier = new AttributeValueSupplier(
this.pageService,
configuration.getModelId());
final EntityTable<TemplateAttribute> attrTable = final EntityTable<TemplateAttribute> attrTable =
this.pageService.entityTableBuilder( this.pageService.entityTableBuilder(
Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template", Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template",
@ -213,6 +238,7 @@ public class ConfigTemplateForm implements TemplateComposer {
API.PARAM_PARENT_MODEL_ID, API.PARAM_PARENT_MODEL_ID,
entityKey.modelId)) entityKey.modelId))
.withPaging(15) .withPaging(15)
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME, Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
ATTRIBUTES_LIST_NAME_TEXT_KEY, ATTRIBUTES_LIST_NAME_TEXT_KEY,
@ -220,6 +246,7 @@ public class ConfigTemplateForm implements TemplateComposer {
.withFilter(this.nameFilter) .withFilter(this.nameFilter)
.sortable() .sortable()
.widthProportion(3)) .widthProportion(3))
.withColumn(new ColumnDefinition<TemplateAttribute>( .withColumn(new ColumnDefinition<TemplateAttribute>(
Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE, Domain.CONFIGURATION_ATTRIBUTE.ATTR_TYPE,
ATTRIBUTES_LIST_TYPE_TEXT_KEY, ATTRIBUTES_LIST_TYPE_TEXT_KEY,
@ -227,6 +254,7 @@ public class ConfigTemplateForm implements TemplateComposer {
.withFilter(typeFilter) .withFilter(typeFilter)
.sortable() .sortable()
.widthProportion(1)) .widthProportion(1))
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.ORIENTATION.ATTR_VIEW_ID, Domain.ORIENTATION.ATTR_VIEW_ID,
ATTRIBUTES_LIST_VIEW_TEXT_KEY, ATTRIBUTES_LIST_VIEW_TEXT_KEY,
@ -234,6 +262,7 @@ public class ConfigTemplateForm implements TemplateComposer {
.withFilter(viewFilter) .withFilter(viewFilter)
.sortable() .sortable()
.widthProportion(1)) .widthProportion(1))
.withColumn(new ColumnDefinition<>( .withColumn(new ColumnDefinition<>(
Domain.ORIENTATION.ATTR_GROUP_ID, Domain.ORIENTATION.ATTR_GROUP_ID,
ATTRIBUTES_LIST_GROUP_TEXT_KEY, ATTRIBUTES_LIST_GROUP_TEXT_KEY,
@ -241,6 +270,13 @@ public class ConfigTemplateForm implements TemplateComposer {
.withFilter(this.groupFilter) .withFilter(this.groupFilter)
.sortable() .sortable()
.widthProportion(1)) .widthProportion(1))
.withColumn(new ColumnDefinition<TemplateAttribute>(
Domain.CONFIGURATION_VALUE.ATTR_VALUE,
ATTRIBUTES_LIST_VALUE_TEXT_KEY,
attr -> attributeValueSupplier.getAttributeValue(attr.getConfigAttribute().id))
.widthProportion(1))
.withDefaultActionIf( .withDefaultActionIf(
() -> modifyGrant, () -> modifyGrant,
() -> pageActionBuilder () -> pageActionBuilder
@ -271,7 +307,7 @@ public class ConfigTemplateForm implements TemplateComposer {
.withParentEntityKey(entityKey) .withParentEntityKey(entityKey)
.withSelect( .withSelect(
attrTable::getMultiSelection, attrTable::getMultiSelection,
action -> this.resetToDefaults(action, attrTable), action -> this.resetToDefaults(attributeValueSupplier, action, attrTable),
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.noEventPropagation() .noEventPropagation()
.publishIf(() -> modifyGrant, false) .publishIf(() -> modifyGrant, false)
@ -378,12 +414,14 @@ public class ConfigTemplateForm implements TemplateComposer {
} }
private PageAction resetToDefaults( private PageAction resetToDefaults(
final AttributeValueSupplier attributeValueSupplier,
final PageAction action, final PageAction action,
final EntityTable<TemplateAttribute> attrTable) { final EntityTable<TemplateAttribute> attrTable) {
final PageAction resetToDefaults = this.examConfigurationService.resetToDefaults(action); final PageAction resetToDefaults = this.examConfigurationService.resetToDefaults(action);
// reload the list // reload the list
attrTable.applyFilter(); attributeValueSupplier.update();
attrTable.updateCurrentPage();
return resetToDefaults; return resetToDefaults;
} }
@ -392,8 +430,8 @@ public class ConfigTemplateForm implements TemplateComposer {
final EntityTable<TemplateAttribute> attrTable) { final EntityTable<TemplateAttribute> attrTable) {
final PageAction removeFormView = this.examConfigurationService.removeFromView(action); final PageAction removeFormView = this.examConfigurationService.removeFromView(action);
// reload the list // reload the page
attrTable.applyFilter(); attrTable.updateCurrentPage();
return removeFormView; return removeFormView;
} }
@ -402,9 +440,54 @@ public class ConfigTemplateForm implements TemplateComposer {
final EntityTable<TemplateAttribute> attrTable) { final EntityTable<TemplateAttribute> attrTable) {
final PageAction attachView = this.examConfigurationService.attachToDefaultView(action); final PageAction attachView = this.examConfigurationService.attachToDefaultView(action);
// reload the list // reload the page
attrTable.applyFilter(); attrTable.updateCurrentPage();
return attachView; return attachView;
} }
private final class AttributeValueSupplier {
private final PageService pageService;
private final String configurationId;
private final Map<Long, String> attrValueMapping = new HashMap<>();
public AttributeValueSupplier(
final PageService pageService,
final String configurationId) {
this.pageService = pageService;
this.configurationId = configurationId;
update();
}
public String getAttributeValue(final Long attributeId) {
if (this.attrValueMapping.containsKey(attributeId)) {
return this.attrValueMapping.get(attributeId);
} else {
return Constants.EMPTY_NOTE;
}
}
private void update() {
this.attrValueMapping.clear();
this.pageService.getRestService()
.getBuilder(GetConfigurationValues.class)
.withQueryParam(
ConfigurationValue.FILTER_ATTR_CONFIGURATION_ID,
this.configurationId)
.call()
.getOrElse(Collections::emptyList)
.stream()
.forEach(val -> {
if (this.attrValueMapping.containsKey(val.attributeId)) {
this.attrValueMapping.put(val.attributeId,
this.attrValueMapping.get(val.attributeId) + "," + val.value);
} else {
this.attrValueMapping.put(val.attributeId, val.value);
}
});
}
}
} }

View file

@ -72,6 +72,11 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
private static final Logger log = LoggerFactory.getLogger(ExamConfigurationServiceImpl.class); private static final Logger log = LoggerFactory.getLogger(ExamConfigurationServiceImpl.class);
public static final LocTextKey ACTION_ERROR_TITLE =
new LocTextKey("sebserver.configtemplate.action.error.title");
public static final LocTextKey ACTION_ERROR_MSG =
new LocTextKey("sebserver.configtemplate.action.error.noview.message");
private final RestService restService; private final RestService restService;
private final JSONMapper jsonMapper; private final JSONMapper jsonMapper;
private final WidgetFactory widgetFactory; private final WidgetFactory widgetFactory;
@ -254,12 +259,14 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
final Set<EntityKey> selection = action.getMultiSelection(); final Set<EntityKey> selection = action.getMultiSelection();
if (selection != null && !selection.isEmpty()) { if (selection != null && !selection.isEmpty()) {
selection.forEach(entityKey -> callTemplateAction( selection.forEach(entityKey -> callTemplateAction(
action,
ResetTemplateValues.class, ResetTemplateValues.class,
parentEntityKey.modelId, parentEntityKey.modelId,
entityKey.modelId)); entityKey.modelId));
} else { } else {
final EntityKey entityKey = action.getEntityKey(); final EntityKey entityKey = action.getEntityKey();
callTemplateAction( callTemplateAction(
action,
ResetTemplateValues.class, ResetTemplateValues.class,
parentEntityKey.modelId, parentEntityKey.modelId,
entityKey.modelId); entityKey.modelId);
@ -274,12 +281,14 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
final Set<EntityKey> selection = action.getMultiSelection(); final Set<EntityKey> selection = action.getMultiSelection();
if (selection != null && !selection.isEmpty()) { if (selection != null && !selection.isEmpty()) {
selection.forEach(entityKey -> callTemplateAction( selection.forEach(entityKey -> callTemplateAction(
action,
RemoveOrientation.class, RemoveOrientation.class,
parentEntityKey.modelId, parentEntityKey.modelId,
entityKey.modelId)); entityKey.modelId));
} else { } else {
final EntityKey entityKey = action.getEntityKey(); final EntityKey entityKey = action.getEntityKey();
callTemplateAction( callTemplateAction(
action,
RemoveOrientation.class, RemoveOrientation.class,
parentEntityKey.modelId, parentEntityKey.modelId,
entityKey.modelId); entityKey.modelId);
@ -294,21 +303,23 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
final Set<EntityKey> selection = action.getMultiSelection(); final Set<EntityKey> selection = action.getMultiSelection();
if (selection != null && !selection.isEmpty()) { if (selection != null && !selection.isEmpty()) {
selection.forEach(entityKey -> callTemplateAction( selection.forEach(entityKey -> callTemplateAction(
action,
AttachDefaultOrientation.class, AttachDefaultOrientation.class,
parentEntityKey.modelId, parentEntityKey.modelId,
entityKey.modelId)); entityKey.modelId));
} else { } else {
final EntityKey entityKey = action.getEntityKey(); final EntityKey entityKey = action.getEntityKey();
callTemplateAction( callTemplateAction(
action,
AttachDefaultOrientation.class, AttachDefaultOrientation.class,
parentEntityKey.modelId, parentEntityKey.modelId,
entityKey.modelId); entityKey.modelId);
} }
return action; return action;
} }
private void callTemplateAction( private void callTemplateAction(
final PageAction action,
final Class<? extends RestCall<TemplateAttribute>> actionType, final Class<? extends RestCall<TemplateAttribute>> actionType,
final String templateId, final String templateId,
final String attributeId) { final String attributeId) {
@ -317,7 +328,11 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
.withURIVariable(API.PARAM_PARENT_MODEL_ID, templateId) .withURIVariable(API.PARAM_PARENT_MODEL_ID, templateId)
.withURIVariable(API.PARAM_MODEL_ID, attributeId) .withURIVariable(API.PARAM_MODEL_ID, attributeId)
.call() .call()
.getOrThrow(); .onError(error -> {
action.pageContext().publishPageMessage(
ACTION_ERROR_TITLE,
ACTION_ERROR_MSG);
});
} }
private static final class ValueChangeListenerImpl implements ValueChangeListener { private static final class ValueChangeListenerImpl implements ValueChangeListener {

View file

@ -300,6 +300,10 @@ public class EntityTable<ROW extends ModelIdAware> {
applyFilter(); applyFilter();
} }
public void updateCurrentPage() {
this.selectPage(this.pageNumber);
}
public void applyFilter() { public void applyFilter() {
try { try {

View file

@ -0,0 +1,27 @@
/*
* Copyright (c) 2022 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.servicelayer.dao;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class NoResourceFoundException extends RuntimeException {
private static final long serialVersionUID = 4347712679241097195L;
public final EntityType entityType;
public NoResourceFoundException(final EntityType entityType, final String message) {
super("Resource " + entityType + " not found: " + message);
this.entityType = entityType;
}
}

View file

@ -25,6 +25,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.Constants; 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.Domain;
import ch.ethz.seb.sebserver.gbl.model.PageSortOrder; import ch.ethz.seb.sebserver.gbl.model.PageSortOrder;
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType; import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
@ -39,6 +40,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeD
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationValueDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationValueDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.NoResourceFoundException;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.OrientationDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.OrientationDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ViewDAO; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ViewDAO;
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigTemplateService; import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ExamConfigTemplateService;
@ -172,7 +174,13 @@ public class ExamConfigTemplateServiceImpl implements ExamConfigTemplateService
return Result.tryCatch(() -> { return Result.tryCatch(() -> {
final Orientation orientation = getOrientation(templateId, attributeId); final Orientation orientation = getOrientation(templateId, attributeId);
this.orientationDAO.delete(new HashSet<>(Arrays.asList(orientation.getEntityKey()))) if (orientation == null) {
throw new NoResourceFoundException(EntityType.ORIENTATION,
"No default view found for attribute: " + attributeId);
}
this.orientationDAO
.delete(new HashSet<>(Arrays.asList(orientation.getEntityKey())))
.getOrThrow(); .getOrThrow();
final TemplateAttribute attribute = getAttribute(institutionId, templateId, attributeId) final TemplateAttribute attribute = getAttribute(institutionId, templateId, attributeId)
@ -198,8 +206,14 @@ public class ExamConfigTemplateServiceImpl implements ExamConfigTemplateService
final Orientation orientation = getOrientation(templateId, attributeId); final Orientation orientation = getOrientation(templateId, attributeId);
final Orientation devOrientation = getOrientation(ConfigurationNode.DEFAULT_TEMPLATE_ID, attributeId); final Orientation devOrientation = getOrientation(ConfigurationNode.DEFAULT_TEMPLATE_ID, attributeId);
if (devOrientation == null) {
throw new NoResourceFoundException(EntityType.ORIENTATION,
"No default view found for attribute: " + attributeId);
}
if (orientation != null) { if (orientation != null) {
this.orientationDAO.delete(new HashSet<>(Arrays.asList(orientation.getEntityKey()))) this.orientationDAO
.delete(new HashSet<>(Arrays.asList(orientation.getEntityKey())))
.getOrThrow(); .getOrThrow();
} }
@ -246,7 +260,7 @@ public class ExamConfigTemplateServiceImpl implements ExamConfigTemplateService
return this.orientationDAO.allMatching(filterMap) return this.orientationDAO.allMatching(filterMap)
.get(error -> { .get(error -> {
log.warn("Unexpecrted error while get Orientation: ", error); log.warn("Unexpected error while get Orientation: ", error);
return Collections.emptyList(); return Collections.emptyList();
}) })
.stream() .stream()

View file

@ -455,7 +455,6 @@ public class ZoomProctoringService implements ExamProctoringService {
e); e);
} }
}); });
} }
@Override @Override

View file

@ -1667,7 +1667,11 @@ sebserver.configtemplate.attrs.list.group=Group
sebserver.configtemplate.attrs.list.group.tooltip=The group on the view/tab where the exam configuration attribute belongs to<br/><br/>{0} sebserver.configtemplate.attrs.list.group.tooltip=The group on the view/tab where the exam configuration attribute belongs to<br/><br/>{0}
sebserver.configtemplate.attrs.list.type=Type sebserver.configtemplate.attrs.list.type=Type
sebserver.configtemplate.attrs.list.type.tooltip=The type of the exam configuration attribute<br/><br/>{0} sebserver.configtemplate.attrs.list.type.tooltip=The type of the exam configuration attribute<br/><br/>{0}
sebserver.configtemplate.attrs.list.value=Value
sebserver.configtemplate.attrs.list.value.tooltip=The settings value that is set as default value for this template
sebserver.configtemplate.action.error.title=Action Failed
sebserver.configtemplate.action.error.noview.message=This setting has no default view<br/>and cannot be attached/detached from a view
sebserver.configtemplate.attr.list.actions= sebserver.configtemplate.attr.list.actions=
sebserver.configtemplate.attr.list.actions.modify=Edit Attribute sebserver.configtemplate.attr.list.actions.modify=Edit Attribute
sebserver.configtemplate.attr.list.actions.setdefault=Set Default Values sebserver.configtemplate.attr.list.actions.setdefault=Set Default Values
@ -1675,6 +1679,7 @@ sebserver.configtemplate.attr.list.actions.removeview=Remove From View
sebserver.configtemplate.attr.list.actions.attach-default-view=Attach To View sebserver.configtemplate.attr.list.actions.attach-default-view=Attach To View
sebserver.configtemplate.attr.info.pleaseSelect=At first please select an Attribute from the list sebserver.configtemplate.attr.info.pleaseSelect=At first please select an Attribute from the list
sebserver.configtemplate.attr.form.title=Configuration Template Attribute sebserver.configtemplate.attr.form.title=Configuration Template Attribute
sebserver.configtemplate.attr.form.title.subtitle= sebserver.configtemplate.attr.form.title.subtitle=
sebserver.configtemplate.attr.form.name=Name sebserver.configtemplate.attr.form.name=Name