SEBSERV-44 SEBSERV-45 finished config tool and some bug fixes
This commit is contained in:
parent
74306412e1
commit
84ac76efd7
45 changed files with 1253 additions and 522 deletions
|
@ -48,7 +48,7 @@ public enum AttributeType {
|
|||
|
||||
INLINE_TABLE(COMPOSITE_LIST),
|
||||
|
||||
;
|
||||
COMPOSITE_TABLE(COMPOSITE);
|
||||
|
||||
public final AttributeValueType attributeValueType;
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ public enum AttributeValueType {
|
|||
BASE64_BINARY,
|
||||
/** A list of single values of the same type */
|
||||
LIST,
|
||||
/** A composite of different typed values like a Map or Dictionary */
|
||||
/** A composite of different typed values like a map or dictionary */
|
||||
COMPOSITE,
|
||||
/** A list of composites of the same type like a Table */
|
||||
/** A list of composites (list of dictionary) of the same type like a Table */
|
||||
COMPOSITE_LIST
|
||||
}
|
||||
|
|
|
@ -8,13 +8,23 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gbl.model.sebconfig;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
|
@ -24,8 +34,25 @@ import ch.ethz.seb.sebserver.gbl.model.Entity;
|
|||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public final class ConfigurationAttribute implements Entity {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ConfigurationAttribute.class);
|
||||
|
||||
/** This configuration attribute dependency key can be used to set a specific localized text key prefix for
|
||||
* resources. This is usually convenient if two different attributes use the same resources and to avoid
|
||||
* to multiply the resources for each attribute with the attribute name prefix, we can set a specific
|
||||
* resourceLocTextKey prefix to use. */
|
||||
public static final String DEPENDENCY_RESOURCE_LOC_TEXT_KEY = "resourceLocTextKey";
|
||||
|
||||
/** This configuration attribute dependency key indicates the group identifier for grouped COMOSITE_TYPE types */
|
||||
public static final String DEPENDENCY_GROUP_ID = "groupId";
|
||||
|
||||
/** This configuration attribute dependency key indicates if a default value should be created even if the
|
||||
* attribute is a child attribute and normally no default value is generated on creation. */
|
||||
public static final String DEPENDENCY_CREATE_DEFAULT_VALUE = "createDefaultValue";
|
||||
|
||||
/** his configuration attribute dependency key indicates if the input field should be shown in the directly
|
||||
* in the View even if the attribute is a child attribute and is usually shown in a table or composite. */
|
||||
public static final String DEPENDENCY_SHOW_IN_VIEW = "showInView";
|
||||
|
||||
public static final String FILTER_ATTR_PARENT_ID = "parentId";
|
||||
public static final String FILTER_ATTR_TYPE = "type";
|
||||
|
||||
|
@ -156,4 +183,55 @@ public final class ConfigurationAttribute implements Entity {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
public static boolean hasDependency(
|
||||
final String dependencyName,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
if (StringUtils.isBlank(attribute.dependencies)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return attribute.dependencies.contains(dependencyName);
|
||||
}
|
||||
|
||||
public static String getDependencyValue(
|
||||
final String dependencyName,
|
||||
final ConfigurationAttribute attribute) {
|
||||
|
||||
return getDependencyValue(dependencyName, attribute.dependencies);
|
||||
}
|
||||
|
||||
public static String getDependencyValue(
|
||||
final String dependencyName,
|
||||
final String dependnciesString) {
|
||||
|
||||
if (StringUtils.isBlank(dependnciesString)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getAttributeDependencyMap(dependnciesString).get(dependencyName);
|
||||
}
|
||||
|
||||
public static Map<String, String> getAttributeDependencyMap(final ConfigurationAttribute attribute) {
|
||||
if (StringUtils.isBlank(attribute.dependencies)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return getAttributeDependencyMap(attribute.dependencies);
|
||||
}
|
||||
|
||||
public static Map<String, String> getAttributeDependencyMap(final String dependnciesString) {
|
||||
try {
|
||||
return Arrays.asList(StringUtils.split(dependnciesString, Constants.LIST_SEPARATOR))
|
||||
.stream()
|
||||
.map(s -> StringUtils.split(s, Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR))
|
||||
.collect(Collectors.toMap(pair -> pair[0], pair -> pair[1]));
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to parse dependency map of: {}",
|
||||
dependnciesString,
|
||||
e);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@ public final class ConfigurationNode implements GrantEntity {
|
|||
@JsonProperty(CONFIGURATION_NODE.ATTR_NAME)
|
||||
public final String name;
|
||||
|
||||
@Size(max = 4000, message = "configurationNode:description:size:{min}:{max}:${validatedValue}")
|
||||
@JsonProperty(CONFIGURATION_NODE.ATTR_DESCRIPTION)
|
||||
public final String description;
|
||||
|
||||
|
|
|
@ -34,7 +34,6 @@ import com.fasterxml.jackson.core.JsonProcessingException;
|
|||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
|
||||
public final class Utils {
|
||||
|
||||
|
@ -294,22 +293,4 @@ public final class Utils {
|
|||
return toCharArray(CharBuffer.wrap(chars));
|
||||
}
|
||||
|
||||
public static Map<String, String> getAttributeDependencyMap(final ConfigurationAttribute attribute) {
|
||||
if (StringUtils.isBlank(attribute.dependencies)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
try {
|
||||
return Arrays.asList(StringUtils.split(attribute.dependencies, Constants.LIST_SEPARATOR))
|
||||
.stream()
|
||||
.map(s -> StringUtils.split(s, Constants.EMBEDDED_LIST_SEPARATOR))
|
||||
.collect(Collectors.toMap(pair -> pair[0], pair -> pair[1]));
|
||||
} catch (final Exception e) {
|
||||
log.error("Unexpected error while trying to parse dependency map of ConfigurationAttribute: {}",
|
||||
attribute,
|
||||
e);
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -65,11 +65,14 @@ public final class SelectionFieldBuilder extends FieldBuilder<String> {
|
|||
}
|
||||
|
||||
private void buildInput(final FormBuilder builder, final Label lab) {
|
||||
|
||||
final String actionKey = (this.label != null) ? this.label.name + ".action" : null;
|
||||
final Selection selection = builder.widgetFactory.selectionLocalized(
|
||||
this.type,
|
||||
builder.formParent,
|
||||
this.itemsSupplier);
|
||||
this.itemsSupplier,
|
||||
null,
|
||||
null,
|
||||
actionKey);
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
|
||||
((Control) selection).setLayoutData(gridData);
|
||||
|
|
|
@ -59,6 +59,9 @@ public final class TextFieldBuilder extends FieldBuilder<String> {
|
|||
: builder.widgetFactory.textInput(builder.formParent, this.isPassword);
|
||||
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1);
|
||||
if (this.isArea) {
|
||||
gridData.heightHint = 50;
|
||||
}
|
||||
textInput.setLayoutData(gridData);
|
||||
if (this.value != null) {
|
||||
textInput.setText(this.value);
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
|
@ -71,12 +72,18 @@ public interface InputFieldBuilder {
|
|||
final GridData gridData = new GridData(
|
||||
SWT.FILL, SWT.FILL,
|
||||
true, false,
|
||||
(orientation != null && attribute.parentId == null) ? orientation.width() : 1,
|
||||
(orientation != null && attribute.parentId == null) ? orientation.height() : 1);
|
||||
(orientation != null && isOnView(attribute)) ? orientation.width() : 1,
|
||||
(orientation != null && isOnView(attribute)) ? orientation.height() : 1);
|
||||
comp.setLayoutData(gridData);
|
||||
return comp;
|
||||
}
|
||||
|
||||
private static boolean isOnView(final ConfigurationAttribute attribute) {
|
||||
return attribute.parentId == null || BooleanUtils.toBoolean(ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_SHOW_IN_VIEW,
|
||||
attribute));
|
||||
}
|
||||
|
||||
static Label createErrorLabel(final Composite innerGrid) {
|
||||
final Label errorLabel = new Label(innerGrid, SWT.NONE);
|
||||
errorLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
|
|
|
@ -18,7 +18,7 @@ public interface ValueChangeRule {
|
|||
|
||||
void applyRule(
|
||||
ViewContext context,
|
||||
ConfigurationAttribute attribut,
|
||||
ConfigurationAttribute attribute,
|
||||
ConfigurationValue value);
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,335 @@
|
|||
/*
|
||||
* 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.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
||||
|
||||
public abstract class AbstractTableFieldBuilder implements InputFieldBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AbstractTableFieldBuilder.class);
|
||||
|
||||
protected final RestService restService;
|
||||
protected final WidgetFactory widgetFactory;
|
||||
protected InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
|
||||
protected AbstractTableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
this.restService = restService;
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) {
|
||||
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
|
||||
}
|
||||
|
||||
protected Table createTable(final Composite parent, final TableContext tableContext) {
|
||||
final Table table = new Table(parent, SWT.NONE | SWT.V_SCROLL);
|
||||
table.setLayout(new GridLayout());
|
||||
final GridData gridData = new GridData(
|
||||
SWT.FILL, SWT.FILL,
|
||||
true, false,
|
||||
(tableContext.orientation != null) ? tableContext.orientation.width() : 1,
|
||||
(tableContext.orientation != null) ? tableContext.orientation.height() : 1);
|
||||
gridData.heightHint = tableContext.orientation.height * 20 + 40;
|
||||
table.setLayoutData(gridData);
|
||||
table.setHeaderVisible(true);
|
||||
table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext));
|
||||
return table;
|
||||
}
|
||||
|
||||
protected TableContext createTableContext(final ConfigurationAttribute attribute, final ViewContext viewContext) {
|
||||
final TableContext tableContext = new TableContext(
|
||||
this.inputFieldBuilderSupplier,
|
||||
this.widgetFactory,
|
||||
this.restService,
|
||||
attribute,
|
||||
viewContext);
|
||||
return tableContext;
|
||||
}
|
||||
|
||||
protected void setSelectionListener(final Table table, final AbstractTableInputField tableField) {
|
||||
table.addListener(SWT.MouseDoubleClick, event -> {
|
||||
final int selectionIndex = table.getSelectionIndex();
|
||||
if (selectionIndex >= 0) {
|
||||
tableField.openForm(selectionIndex);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void adaptColumnWidth(
|
||||
final Table table,
|
||||
final TableContext tableContext) {
|
||||
|
||||
try {
|
||||
final int currentTableWidth = table.getClientArea().width - 50;
|
||||
final TableColumn[] columns = table.getColumns();
|
||||
final List<Orientation> orientations = tableContext
|
||||
.getColumnAttributes()
|
||||
.stream()
|
||||
.map(attr -> tableContext.getOrientation(attr.id))
|
||||
.collect(Collectors.toList());
|
||||
final Integer div = orientations
|
||||
.stream()
|
||||
.map(o -> o.width)
|
||||
.reduce(0, (acc, val) -> acc + val);
|
||||
final int widthUnit = currentTableWidth / div;
|
||||
for (int i = 0; i < columns.length - 2; i++) {
|
||||
columns[i].setWidth(widthUnit * orientations.get(i).width);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
protected static void setValueToCell(
|
||||
final TableContext tableContext,
|
||||
final TableItem item,
|
||||
final int cellIndex,
|
||||
final ConfigurationAttribute attribute,
|
||||
final TableValue tableValue) {
|
||||
|
||||
switch (attribute.type) {
|
||||
case CHECKBOX: {
|
||||
item.setImage(
|
||||
cellIndex,
|
||||
(BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null))
|
||||
? ImageIcon.YES.getImage(item.getDisplay())
|
||||
: ImageIcon.NO.getImage(item.getDisplay()));
|
||||
break;
|
||||
}
|
||||
case SINGLE_SELECTION: {
|
||||
final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.getName() + "." +
|
||||
tableValue.value;
|
||||
item.setText(
|
||||
cellIndex,
|
||||
tableContext.i18nSupport().getText(key, getValue(attribute, tableValue)));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
item.setText(cellIndex, getValue(attribute, tableValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static String getValue(
|
||||
final ConfigurationAttribute attribute,
|
||||
final TableValue tableValue) {
|
||||
|
||||
if (tableValue == null) {
|
||||
if (StringUtils.isBlank(attribute.defaultValue)) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
} else {
|
||||
return attribute.defaultValue;
|
||||
}
|
||||
} else {
|
||||
if (StringUtils.isBlank(tableValue.value)) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
} else {
|
||||
return tableValue.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static abstract class AbstractTableInputField extends AbstractInputField<Table> {
|
||||
|
||||
protected final TableContext tableContext;
|
||||
|
||||
protected AbstractTableInputField(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation,
|
||||
final Table control,
|
||||
final Label errorLabel,
|
||||
final TableContext tableContext) {
|
||||
|
||||
super(attribute, orientation, control, errorLabel);
|
||||
this.tableContext = tableContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationValue initValue(final Collection<ConfigurationValue> values) {
|
||||
clearTable();
|
||||
// get all child values as TableValues
|
||||
final List<TableValue> tableValues = getChildValues(
|
||||
this.tableContext,
|
||||
this.attribute,
|
||||
values);
|
||||
|
||||
initValue(tableValues);
|
||||
return null;
|
||||
}
|
||||
|
||||
abstract void initValue(final List<TableValue> tableValues);
|
||||
|
||||
abstract void openForm(final int selectionIndex);
|
||||
|
||||
abstract void applyTableRowValues(final int index);
|
||||
|
||||
protected List<TableValue> getChildValues(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final Collection<ConfigurationValue> values) {
|
||||
|
||||
return values.stream()
|
||||
.filter(v -> isChildValue(tableContext, attribute, v))
|
||||
.map(TableValue::of)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
protected boolean isChildValue(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (!tableContext.getViewContext().attributeMapping.attributeIdMapping
|
||||
.containsKey(value.attributeId)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
|
||||
while (attr.parentId != null) {
|
||||
if (attribute.id.equals(attr.parentId)) {
|
||||
return true;
|
||||
}
|
||||
attr = tableContext.getAttribute(attr.parentId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) {
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>();
|
||||
for (final TableValue tableValue : tableValues) {
|
||||
final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent(
|
||||
tableValue.listIndex,
|
||||
key -> new HashMap<>());
|
||||
rowValues.put(tableValue.attributeId, tableValue);
|
||||
}
|
||||
return indexMapping;
|
||||
}
|
||||
|
||||
protected void valuesFromIndexMap(
|
||||
final List<Map<Long, TableValue>> values,
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping) {
|
||||
|
||||
values.clear();
|
||||
final List<Integer> rows = new ArrayList<>(indexMapping.keySet());
|
||||
rows.sort((i1, i2) -> i1.compareTo(i2));
|
||||
rows
|
||||
.stream()
|
||||
.forEach(i -> {
|
||||
final Map<Long, TableValue> rowValues = indexMapping.get(i);
|
||||
values.add(rowValues);
|
||||
// addTableRow(rowValues);
|
||||
});
|
||||
// for (int i = 0; i < rows.size(); i++) {
|
||||
// final Map<Long, TableValue> rowValues = indexMapping.get(i);
|
||||
// values.add(rowValues);
|
||||
// addTableRow(rowValues);
|
||||
// }
|
||||
}
|
||||
|
||||
protected void applyFormValues(
|
||||
final List<Map<Long, TableValue>> values,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final int index) {
|
||||
|
||||
if (values != null && !values.isEmpty()) {
|
||||
values.remove(index);
|
||||
values.add(index, rowValues);
|
||||
applyTableRowValues(index);
|
||||
}
|
||||
|
||||
// send values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(values));
|
||||
}
|
||||
|
||||
protected ConfigurationTableValues extractTableValue(final List<Map<Long, TableValue>> values) {
|
||||
final List<TableValue> collect = values
|
||||
.stream()
|
||||
.flatMap(map -> map.values().stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
collect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultValue() {
|
||||
// NOTE this just empty the list for now
|
||||
// TODO do we need default values for lists?
|
||||
clearTable();
|
||||
final List<TableValue> values = new ArrayList<>();
|
||||
this.tableContext.getValueChangeListener().tableChanged(
|
||||
new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
values));
|
||||
}
|
||||
|
||||
void clearTable() {
|
||||
this.control.setSelection(-1);
|
||||
if (this.control.getItemCount() > 0) {
|
||||
for (final TableItem item : this.control.getItems()) {
|
||||
item.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
/*
|
||||
* 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.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
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.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
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.page.impl.ModalInputDialog;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class CompositeTableFieldBuilder extends AbstractTableFieldBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(CompositeTableFieldBuilder.class);
|
||||
|
||||
private static final String TABLE_ENTRY_NAME = "TABLE_ENTRY";
|
||||
private static final String TABLE_COLUMN_NAME_KEY = "TABLE_COLUMN_NAME";
|
||||
|
||||
protected CompositeTableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
super(restService, widgetFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
final Orientation orientation) {
|
||||
|
||||
if (attribute == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return AttributeType.COMPOSITE_TABLE == attribute.type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputField createInputField(
|
||||
final Composite parent,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final I18nSupport i18nSupport = viewContext.getI18nSupport();
|
||||
final TableContext tableContext = createTableContext(attribute, viewContext);
|
||||
final Table table = createTable(parent, tableContext);
|
||||
|
||||
final String resources = attribute.getResources();
|
||||
final String[] columnsAndRows = StringUtils.split(
|
||||
resources,
|
||||
Constants.EMBEDDED_LIST_SEPARATOR);
|
||||
final String[] columns = (columnsAndRows.length == 2)
|
||||
? StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR)
|
||||
: new String[] { TABLE_ENTRY_NAME };
|
||||
final String[] rows = (columnsAndRows.length == 2)
|
||||
? StringUtils.split(columnsAndRows[1], Constants.LIST_SEPARATOR)
|
||||
: StringUtils.split(columnsAndRows[0], Constants.LIST_SEPARATOR);
|
||||
|
||||
final String attributeNameKey = ExamConfigurationService.attributeNameKey(attribute);
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
final TableColumn column = this.widgetFactory.tableColumnLocalized(
|
||||
table,
|
||||
new LocTextKey(attributeNameKey + "." + columns[i]),
|
||||
new LocTextKey(attributeNameKey + "." + columns[i] + ".tootlip"));
|
||||
|
||||
column.setData(TABLE_COLUMN_NAME_KEY, columns[i]);
|
||||
column.setWidth(100);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
}
|
||||
|
||||
for (int i = 0; i < rows.length; i++) {
|
||||
final TableItem item = new TableItem(table, SWT.NONE);
|
||||
for (int j = 0; j < columns.length; j++) {
|
||||
if (TABLE_ENTRY_NAME.equals(columns[j])) {
|
||||
item.setText(j, i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + rows[i],
|
||||
rows[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final CompositeTableInputField tableField = new CompositeTableInputField(
|
||||
tableContext,
|
||||
table,
|
||||
Arrays.asList(columns),
|
||||
Arrays.asList(rows));
|
||||
|
||||
setSelectionListener(table, tableField);
|
||||
return tableField;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void adaptColumnWidth(
|
||||
final Table table,
|
||||
final TableContext tableContext) {
|
||||
|
||||
try {
|
||||
final int currentTableWidth = table.getClientArea().width - 50;
|
||||
final TableColumn[] columns = table.getColumns();
|
||||
final int widthUnit = currentTableWidth / (columns.length + 2);
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
final int factor = (TABLE_ENTRY_NAME.equals(columns[i].getData(TABLE_COLUMN_NAME_KEY))) ? 4 : 1;
|
||||
columns[i].setWidth(widthUnit * factor);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
static final class CompositeTableInputField extends AbstractTableInputField {
|
||||
|
||||
final List<String> columns;
|
||||
final List<String> rows;
|
||||
final List<Map<Long, TableValue>> values;
|
||||
|
||||
CompositeTableInputField(
|
||||
final TableContext tableContext,
|
||||
final Table control,
|
||||
final List<String> columns,
|
||||
final List<String> rows) {
|
||||
|
||||
super(tableContext.attribute, tableContext.orientation, control, null, tableContext);
|
||||
this.values = new ArrayList<>();
|
||||
this.columns = columns;
|
||||
this.rows = rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
void initValue(final List<TableValue> tableValues) {
|
||||
valuesFromIndexMap(this.values, createRowIndexMap(tableValues));
|
||||
for (int i = 0; i < this.values.size(); i++) {
|
||||
setRowValues(i, this.values.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTableRowValues(final int index) {
|
||||
setRowValues(index, this.values.get(index));
|
||||
}
|
||||
|
||||
private void setRowValues(final int index, final Map<Long, TableValue> map) {
|
||||
final TableItem rowItem = this.control.getItem(index);
|
||||
for (final TableValue val : map.values()) {
|
||||
final Orientation orientation = this.tableContext.getOrientation(val.attributeId);
|
||||
final String groupId = orientation.getGroupId();
|
||||
if (StringUtils.isNoneBlank(groupId)) {
|
||||
final int cellIndex = this.columns.indexOf(groupId);
|
||||
if (cellIndex >= 0) {
|
||||
setValueToCell(
|
||||
this.tableContext,
|
||||
rowItem,
|
||||
cellIndex,
|
||||
this.tableContext.getAttribute(val.attributeId),
|
||||
val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openForm(final int selectionIndex) {
|
||||
final String row = this.rows.get(selectionIndex);
|
||||
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
|
||||
final TableRowFormBuilder builder = new TableRowFormBuilder(
|
||||
this.tableContext,
|
||||
rowValues,
|
||||
row);
|
||||
|
||||
new ModalInputDialog<Map<Long, TableValue>>(
|
||||
this.control.getShell(),
|
||||
this.tableContext.getWidgetFactory())
|
||||
.setDialogWidth(500)
|
||||
.open(
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + row),
|
||||
rowVals -> applyFormValues(this.values, rowVals, selectionIndex),
|
||||
() -> this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue(this.values)),
|
||||
builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<Integer, Map<Long, TableValue>> createRowIndexMap(final List<TableValue> tableValues) {
|
||||
final Map<Integer, Map<Long, TableValue>> indexMapping = new HashMap<>();
|
||||
for (final TableValue tableValue : tableValues) {
|
||||
final ConfigurationAttribute attribute = this.tableContext
|
||||
.getViewContext()
|
||||
.getAttribute(tableValue.attributeId);
|
||||
final String groupId = ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_GROUP_ID,
|
||||
attribute);
|
||||
final int index = this.rows.indexOf(groupId);
|
||||
final Map<Long, TableValue> rowValues = indexMapping.computeIfAbsent(
|
||||
index,
|
||||
key -> new HashMap<>());
|
||||
rowValues.put(tableValue.attributeId, tableValue);
|
||||
}
|
||||
return indexMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
void clearTable() {
|
||||
// nothing to clear for this table type
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isChildValue(
|
||||
final TableContext tableContext,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
final boolean childValue = super.isChildValue(tableContext, attribute, value);
|
||||
if (childValue) {
|
||||
final ConfigurationAttribute attr = tableContext.getAttribute(value.attributeId);
|
||||
return ConfigurationAttribute.hasDependency(
|
||||
ConfigurationAttribute.DEPENDENCY_GROUP_ID,
|
||||
attr);
|
||||
}
|
||||
|
||||
return childValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -166,7 +166,6 @@ public class ExamConfigurationServiceImpl implements ExamConfigurationService {
|
|||
gridLayout.verticalSpacing = 0;
|
||||
composite.setLayout(gridLayout);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
gridData.heightHint = 200;
|
||||
composite.setLayoutData(gridData);
|
||||
|
||||
final ViewGridBuilder viewGridBuilder = new ViewGridBuilder(
|
||||
|
|
|
@ -8,9 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
@ -20,14 +17,22 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
|||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class LabelBuilder implements InputFieldBuilder {
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
|
||||
protected LabelBuilder(final WidgetFactory widgetFactory) {
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean builderFor(
|
||||
final ConfigurationAttribute attribute,
|
||||
|
@ -46,12 +51,9 @@ public class LabelBuilder implements InputFieldBuilder {
|
|||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
Objects.requireNonNull(parent);
|
||||
Objects.requireNonNull(attribute);
|
||||
Objects.requireNonNull(viewContext);
|
||||
|
||||
final Label label = new Label(parent, SWT.NONE);
|
||||
label.setText(attribute.name);
|
||||
final Label label = this.widgetFactory.labelLocalized(
|
||||
parent,
|
||||
ExamConfigurationService.attributeNameLocKey(attribute));
|
||||
|
||||
return new LabelField(
|
||||
attribute,
|
||||
|
|
|
@ -11,7 +11,6 @@ package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -19,7 +18,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
|
||||
public abstract class SelectionFieldBuilder {
|
||||
|
@ -47,11 +45,14 @@ public abstract class SelectionFieldBuilder {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
final Map<String, String> attributeDependencyMap = Utils.getAttributeDependencyMap(attribute);
|
||||
final String prefix =
|
||||
(attributeDependencyMap.containsKey(ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY))
|
||||
? attributeDependencyMap.get(ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY) + "."
|
||||
: ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".";
|
||||
(ConfigurationAttribute.hasDependency(
|
||||
ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY,
|
||||
attribute))
|
||||
? ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_RESOURCE_LOC_TEXT_KEY,
|
||||
attribute) + "."
|
||||
: ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + attribute.name + ".";
|
||||
|
||||
return Arrays.asList(StringUtils.split(
|
||||
attribute.resources,
|
||||
|
|
|
@ -16,21 +16,18 @@ import java.util.Objects;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.ResourceService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigTableRowValues;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
@ -78,6 +75,10 @@ public class TableContext {
|
|||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public I18nSupport i18nSupport() {
|
||||
return this.viewContext.i18nSupport;
|
||||
}
|
||||
|
||||
public InputFieldBuilderSupplier getInputFieldBuilderSupplier() {
|
||||
return this.inputFieldBuilderSupplier;
|
||||
}
|
||||
|
@ -102,6 +103,20 @@ public class TableContext {
|
|||
return this.rowAttributes;
|
||||
}
|
||||
|
||||
public List<ConfigurationAttribute> getRowAttributes(final String rowGroupId) {
|
||||
if (StringUtils.isBlank(rowGroupId)) {
|
||||
return getRowAttributes();
|
||||
} else {
|
||||
return this.rowAttributes
|
||||
.stream()
|
||||
.filter(attr -> rowGroupId.equals(ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_GROUP_ID,
|
||||
attr)))
|
||||
.sorted(rowAttributeComparator(this.viewContext))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
public List<ConfigurationAttribute> getColumnAttributes() {
|
||||
return this.columnAttributes;
|
||||
}
|
||||
|
@ -188,31 +203,4 @@ public class TableContext {
|
|||
};
|
||||
}
|
||||
|
||||
public String getRowValue(final TableValue tableValue) {
|
||||
if (tableValue == null || StringUtils.isBlank(tableValue.value)) {
|
||||
return Constants.EMPTY_NOTE;
|
||||
}
|
||||
|
||||
final ConfigurationAttribute attribute = this.viewContext.getAttribute(tableValue.attributeId);
|
||||
if (attribute != null) {
|
||||
switch (attribute.type) {
|
||||
case CHECKBOX: {
|
||||
return BooleanUtils.toBoolean(tableValue.value)
|
||||
? this.viewContext.i18nSupport.getText(ResourceService.ACTIVE_TEXT_KEY)
|
||||
: this.viewContext.i18nSupport.getText(ResourceService.INACTIVE_TEXT_KEY);
|
||||
}
|
||||
case SINGLE_SELECTION: {
|
||||
final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
attribute.getName() + "." +
|
||||
tableValue.value;
|
||||
return this.viewContext.i18nSupport.getText(key, tableValue.value);
|
||||
}
|
||||
default:
|
||||
return tableValue.value;
|
||||
}
|
||||
}
|
||||
|
||||
return tableValue.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,37 +9,27 @@
|
|||
package ch.ethz.seb.sebserver.gui.service.examconfig.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
import org.eclipse.swt.widgets.TableColumn;
|
||||
import org.eclipse.swt.widgets.TableItem;
|
||||
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.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
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.page.impl.ModalInputDialog;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
|
||||
|
@ -48,27 +38,13 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon;
|
|||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class TableFieldBuilder implements InputFieldBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TableFieldBuilder.class);
|
||||
|
||||
private static final String ROW_VALUE_KEY = "RowValues";
|
||||
|
||||
private final RestService restService;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private InputFieldBuilderSupplier inputFieldBuilderSupplier;
|
||||
public class TableFieldBuilder extends AbstractTableFieldBuilder {
|
||||
|
||||
protected TableFieldBuilder(
|
||||
final RestService restService,
|
||||
final WidgetFactory widgetFactory) {
|
||||
|
||||
this.restService = restService;
|
||||
this.widgetFactory = widgetFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(final InputFieldBuilderSupplier inputFieldBuilderSupplier) {
|
||||
this.inputFieldBuilderSupplier = inputFieldBuilderSupplier;
|
||||
super(restService, widgetFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,35 +65,20 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
final ConfigurationAttribute attribute,
|
||||
final ViewContext viewContext) {
|
||||
|
||||
final I18nSupport i18nSupport = viewContext.getI18nSupport();
|
||||
final TableContext tableContext = new TableContext(
|
||||
this.inputFieldBuilderSupplier,
|
||||
this.widgetFactory,
|
||||
this.restService,
|
||||
attribute,
|
||||
viewContext);
|
||||
|
||||
final Table table = new Table(parent, SWT.NONE | SWT.H_SCROLL);
|
||||
table.setLayout(new GridLayout());
|
||||
final GridData gridData = new GridData(
|
||||
SWT.FILL, SWT.FILL,
|
||||
true, false,
|
||||
(tableContext.orientation != null) ? tableContext.orientation.width() : 1,
|
||||
(tableContext.orientation != null) ? tableContext.orientation.height() : 1);
|
||||
gridData.heightHint = tableContext.orientation.height * 20 + 40;
|
||||
table.setLayoutData(gridData);
|
||||
table.setHeaderVisible(true);
|
||||
table.addListener(SWT.Resize, event -> adaptColumnWidth(table, tableContext));
|
||||
final TableContext tableContext = createTableContext(attribute, viewContext);
|
||||
final Table table = createTable(parent, tableContext);
|
||||
|
||||
for (final ConfigurationAttribute columnAttribute : tableContext.getColumnAttributes()) {
|
||||
final TableColumn column = new TableColumn(table, SWT.NONE);
|
||||
final String text = i18nSupport.getText(
|
||||
ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
columnAttribute.name,
|
||||
columnAttribute.name);
|
||||
column.setText(text);
|
||||
final TableColumn column = this.widgetFactory.tableColumnLocalized(
|
||||
table,
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
columnAttribute.name),
|
||||
new LocTextKey(ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX +
|
||||
columnAttribute.name +
|
||||
".tootltip"));
|
||||
column.setWidth(100);
|
||||
column.setResizable(false);
|
||||
column.setMoveable(false);
|
||||
}
|
||||
|
||||
final TableInputField tableField = new TableInputField(
|
||||
|
@ -149,107 +110,28 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
}
|
||||
});
|
||||
|
||||
table.addListener(SWT.MouseDoubleClick, event -> {
|
||||
final int selectionIndex = table.getSelectionIndex();
|
||||
if (selectionIndex >= 0) {
|
||||
tableField.openForm(selectionIndex);
|
||||
}
|
||||
});
|
||||
|
||||
setSelectionListener(table, tableField);
|
||||
return tableField;
|
||||
}
|
||||
|
||||
private void adaptColumnWidth(
|
||||
final Table table,
|
||||
final TableContext tableContext) {
|
||||
static final class TableInputField extends AbstractTableInputField {
|
||||
|
||||
try {
|
||||
final int currentTableWidth = table.getClientArea().width - 50;
|
||||
final TableColumn[] columns = table.getColumns();
|
||||
final List<Orientation> orientations = tableContext
|
||||
.getColumnAttributes()
|
||||
.stream()
|
||||
.map(attr -> tableContext.getOrientation(attr.id))
|
||||
.collect(Collectors.toList());
|
||||
final Integer div = orientations
|
||||
.stream()
|
||||
.map(o -> o.width)
|
||||
.reduce(0, (acc, val) -> acc + val);
|
||||
final int widthUnit = currentTableWidth / div;
|
||||
for (int i = 0; i < columns.length - 2; i++) {
|
||||
columns[i].setWidth(widthUnit * orientations.get(i).width);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
log.warn("Failed to adaptColumnWidth: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
static final class TableInputField extends AbstractInputField<Table> {
|
||||
|
||||
private final TableContext tableContext;
|
||||
|
||||
private List<Map<Long, TableValue>> values;
|
||||
private final List<Map<Long, TableValue>> values;
|
||||
|
||||
TableInputField(
|
||||
final TableContext tableContext,
|
||||
final Table control) {
|
||||
|
||||
super(tableContext.attribute, tableContext.orientation, control, null);
|
||||
this.tableContext = tableContext;
|
||||
super(tableContext.attribute, tableContext.orientation, control, null, tableContext);
|
||||
this.values = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigurationValue initValue(final Collection<ConfigurationValue> values) {
|
||||
clearTable();
|
||||
// get all child values as TableValues
|
||||
final List<TableValue> tableValues = values.stream()
|
||||
.filter(this::isChildValue)
|
||||
.map(TableValue::of)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
initValue(tableValues);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void initValue(final List<TableValue> tableValues) {
|
||||
final Map<Integer, Map<Long, TableValue>> _initValue = new HashMap<>();
|
||||
for (final TableValue tableValue : tableValues) {
|
||||
final Map<Long, TableValue> rowValues = _initValue.computeIfAbsent(
|
||||
tableValue.listIndex,
|
||||
key -> new HashMap<>());
|
||||
rowValues.put(tableValue.attributeId, tableValue);
|
||||
valuesFromIndexMap(this.values, createRowIndexMap(tableValues));
|
||||
for (int i = 0; i < this.values.size(); i++) {
|
||||
addTableRow(i, this.values.get(i));
|
||||
}
|
||||
|
||||
final List<Integer> rows = new ArrayList<>(_initValue.keySet());
|
||||
rows.sort((i1, i2) -> i1.compareTo(i2));
|
||||
|
||||
this.values = new ArrayList<>();
|
||||
rows
|
||||
.stream()
|
||||
.forEach(i -> {
|
||||
final Map<Long, TableValue> rowValues = _initValue.get(i);
|
||||
this.values.add(rowValues);
|
||||
addTableRow(rowValues);
|
||||
});
|
||||
}
|
||||
|
||||
private boolean isChildValue(final ConfigurationValue value) {
|
||||
if (!this.tableContext.getViewContext().attributeMapping.attributeIdMapping
|
||||
.containsKey(value.attributeId)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ConfigurationAttribute attr = this.tableContext.getAttribute(value.attributeId);
|
||||
while (attr.parentId != null) {
|
||||
if (this.attribute.id.equals(attr.parentId)) {
|
||||
return true;
|
||||
}
|
||||
attr = this.tableContext.getAttribute(attr.parentId);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void deleteRow(final int selectionIndex) {
|
||||
|
@ -257,7 +139,7 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
this.values.remove(selectionIndex);
|
||||
// send new values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue());
|
||||
.tableChanged(extractTableValue(this.values));
|
||||
}
|
||||
|
||||
private void addRow() {
|
||||
|
@ -271,21 +153,22 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
Function.identity()));
|
||||
|
||||
this.values.add(rowValues);
|
||||
addTableRow(rowValues);
|
||||
addTableRow(this.values.size() - 1, rowValues);
|
||||
this.control.layout();
|
||||
// send new values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue());
|
||||
.tableChanged(extractTableValue(this.values));
|
||||
}
|
||||
|
||||
private void addTableRow(final Map<Long, TableValue> rowValues) {
|
||||
protected void addTableRow(final int index, final Map<Long, TableValue> rowValues) {
|
||||
new TableItem(this.control, SWT.NONE);
|
||||
applyTableRowValues(this.values.size() - 1);
|
||||
applyTableRowValues(index);
|
||||
|
||||
// TODO try to add delete button within table row?
|
||||
}
|
||||
|
||||
private void applyTableRowValues(final int index) {
|
||||
@Override
|
||||
protected void applyTableRowValues(final int index) {
|
||||
final TableItem item = this.control.getItem(index);
|
||||
final Map<Long, TableValue> rowValues = this.values.get(index);
|
||||
|
||||
|
@ -293,26 +176,14 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
for (final ConfigurationAttribute attr : this.tableContext.getColumnAttributes()) {
|
||||
if (rowValues.containsKey(attr.id)) {
|
||||
final TableValue tableValue = rowValues.get(attr.id);
|
||||
if (attr.type == AttributeType.CHECKBOX) {
|
||||
|
||||
item.setImage(
|
||||
cellIndex,
|
||||
(BooleanUtils.toBoolean((tableValue != null) ? tableValue.value : null))
|
||||
? ImageIcon.YES.getImage(this.control.getDisplay())
|
||||
: ImageIcon.NO.getImage(this.control.getDisplay()));
|
||||
} else {
|
||||
item.setText(
|
||||
cellIndex,
|
||||
this.tableContext.getRowValue(tableValue));
|
||||
}
|
||||
setValueToCell(this.tableContext, item, cellIndex, attr, tableValue);
|
||||
}
|
||||
cellIndex++;
|
||||
}
|
||||
|
||||
item.setData(ROW_VALUE_KEY, item);
|
||||
}
|
||||
|
||||
private void openForm(final int selectionIndex) {
|
||||
@Override
|
||||
protected void openForm(final int selectionIndex) {
|
||||
final Map<Long, TableValue> rowValues = this.values.get(selectionIndex);
|
||||
final TableRowFormBuilder builder = new TableRowFormBuilder(
|
||||
this.tableContext,
|
||||
|
@ -327,69 +198,12 @@ public class TableFieldBuilder implements InputFieldBuilder {
|
|||
ExamConfigurationService.getTablePopupTitleKey(
|
||||
this.attribute,
|
||||
this.tableContext.getViewContext().i18nSupport),
|
||||
values -> applyFormValues(values, selectionIndex),
|
||||
rowVals -> applyFormValues(this.values, rowVals, selectionIndex),
|
||||
() -> this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue()),
|
||||
.tableChanged(extractTableValue(this.values)),
|
||||
builder);
|
||||
}
|
||||
|
||||
private void applyFormValues(final Map<Long, TableValue> values, final int index) {
|
||||
if (values != null && !values.isEmpty()) {
|
||||
this.values.remove(index);
|
||||
this.values.add(index, values);
|
||||
applyTableRowValues(index);
|
||||
}
|
||||
|
||||
// send values to web-service
|
||||
this.tableContext.getValueChangeListener()
|
||||
.tableChanged(extractTableValue());
|
||||
}
|
||||
|
||||
private ConfigurationTableValues extractTableValue() {
|
||||
final List<TableValue> collect = this.values
|
||||
.stream()
|
||||
.flatMap(map -> map.values().stream())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
collect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDefaultValue() {
|
||||
// NOTE this just empty the list for now
|
||||
// TODO do we need default values for lists?
|
||||
clearTable();
|
||||
final List<TableValue> values = new ArrayList<>();
|
||||
this.tableContext.getValueChangeListener().tableChanged(
|
||||
new ConfigurationTableValues(
|
||||
this.tableContext.getInstitutionId(),
|
||||
this.tableContext.getConfigurationId(),
|
||||
this.attribute.id,
|
||||
values));
|
||||
}
|
||||
|
||||
private void clearTable() {
|
||||
this.control.setSelection(-1);
|
||||
if (this.control.getItemCount() > 0) {
|
||||
for (final TableItem item : this.control.getItems()) {
|
||||
item.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValueToControl(final String value) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,11 +25,11 @@ import org.eclipse.swt.widgets.Label;
|
|||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.TableFieldBuilder.TableInputField;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ModalInputDialogComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageService;
|
||||
|
@ -40,6 +40,7 @@ public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, T
|
|||
private final TableContext tableContext;
|
||||
private final Map<Long, TableValue> rowValues;
|
||||
private final int listIndex;
|
||||
private final String rowGroupId;
|
||||
|
||||
public TableRowFormBuilder(
|
||||
final TableContext tableContext,
|
||||
|
@ -49,6 +50,18 @@ public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, T
|
|||
this.tableContext = tableContext;
|
||||
this.rowValues = rowValues;
|
||||
this.listIndex = listIndex;
|
||||
this.rowGroupId = null;
|
||||
}
|
||||
|
||||
public TableRowFormBuilder(
|
||||
final TableContext tableContext,
|
||||
final Map<Long, TableValue> rowValues,
|
||||
final String rowGroupId) {
|
||||
|
||||
this.tableContext = tableContext;
|
||||
this.rowValues = rowValues;
|
||||
this.listIndex = 0;
|
||||
this.rowGroupId = rowGroupId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -67,11 +80,25 @@ public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, T
|
|||
false);
|
||||
|
||||
final List<InputField> inputFields = new ArrayList<>();
|
||||
for (final ConfigurationAttribute attribute : this.tableContext.getRowAttributes()) {
|
||||
for (final ConfigurationAttribute attribute : this.tableContext.getRowAttributes(this.rowGroupId)) {
|
||||
createLabel(grid, attribute);
|
||||
inputFields.add(createInputField(grid, attribute));
|
||||
}
|
||||
|
||||
for (final InputField inputField : inputFields) {
|
||||
final ConfigurationAttribute attribute = inputField.getAttribute();
|
||||
this.tableContext.getValueChangeListener().notifyGUI(
|
||||
this.tableContext.getViewContext(),
|
||||
attribute,
|
||||
new ConfigurationValue(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
attribute.id,
|
||||
this.listIndex,
|
||||
inputField.getValue()));
|
||||
}
|
||||
|
||||
// when the pop-up gets closed we have to remove the input fields from the view context
|
||||
grid.addDisposeListener(event -> {
|
||||
this.tableContext.flushInputFields(this.rowValues.keySet());
|
||||
|
@ -103,14 +130,8 @@ public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, T
|
|||
attribute,
|
||||
this.tableContext.getViewContext());
|
||||
|
||||
if (attribute.type == AttributeType.TABLE) {
|
||||
((TableInputField) inputField).initValue(new ArrayList<>(this.rowValues.values()));
|
||||
} else {
|
||||
inputField.initValue(
|
||||
this.rowValues.get(attribute.id).value,
|
||||
this.listIndex);
|
||||
}
|
||||
|
||||
final TableValue initValue = this.rowValues.get(attribute.id);
|
||||
inputField.initValue((initValue != null) ? initValue.value : null, this.listIndex);
|
||||
// we have to register the input field within the ViewContext to receive error messages
|
||||
this.tableContext.registerInputField(inputField);
|
||||
|
||||
|
|
|
@ -64,14 +64,23 @@ public class TextFieldBuilder implements InputFieldBuilder {
|
|||
.createInnerGrid(parent, attribute, orientation);
|
||||
|
||||
final Text text;
|
||||
if (attribute.type == AttributeType.INTEGER ||
|
||||
attribute.type == AttributeType.DECIMAL) {
|
||||
|
||||
text = new Text(innerGrid, SWT.RIGHT | SWT.BORDER);
|
||||
} else {
|
||||
text = new Text(innerGrid, SWT.LEFT | SWT.BORDER);
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false);
|
||||
switch (attribute.type) {
|
||||
case INTEGER:
|
||||
case DECIMAL: {
|
||||
text = new Text(innerGrid, SWT.RIGHT | SWT.BORDER);
|
||||
break;
|
||||
}
|
||||
case TEXT_AREA: {
|
||||
text = new Text(innerGrid, SWT.LEFT | SWT.BORDER | SWT.MULTI);
|
||||
gridData.heightHint = 50;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
text = new Text(innerGrid, SWT.LEFT | SWT.BORDER);
|
||||
}
|
||||
}
|
||||
text.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
text.setLayoutData(gridData);
|
||||
|
||||
final LocTextKey toolTipKey = ExamConfigurationService.getToolTipKey(
|
||||
attribute,
|
||||
|
|
|
@ -96,10 +96,6 @@ public final class ViewContext {
|
|||
public View getView() {
|
||||
return this.view;
|
||||
}
|
||||
//
|
||||
// public AttributeMapping getAttributeMapping() {
|
||||
// return this.attributeMapping;
|
||||
// }
|
||||
|
||||
public Collection<ConfigurationAttribute> getChildAttributes(final Long id) {
|
||||
return this.attributeMapping.childAttributeMapping.get(id);
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Arrays;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
|
@ -71,8 +72,12 @@ public class ViewGridBuilder {
|
|||
log.debug("Add SEB Configuration Attribute: " + attribute);
|
||||
}
|
||||
|
||||
// ignore nested attributes here
|
||||
if (attribute.parentId != null) {
|
||||
// ignore nested attributes here (if not propagated to show up in view)
|
||||
if (attribute.parentId != null &&
|
||||
!BooleanUtils.toBoolean(ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_SHOW_IN_VIEW,
|
||||
attribute))) {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ public class AllowFlashFullscreenRule implements ValueChangeRule {
|
|||
@Override
|
||||
public void applyRule(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribut,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (BooleanUtils.toBoolean(value.value)) {
|
||||
|
|
|
@ -39,7 +39,7 @@ public class BrowserViewModeRule implements ValueChangeRule {
|
|||
@Override
|
||||
public void applyRule(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribut,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (StringUtils.isBlank(value.value)) {
|
||||
|
|
|
@ -34,7 +34,7 @@ public class ExitKeySequenceChangeRule implements ValueChangeRule {
|
|||
@Override
|
||||
public void applyRule(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribut,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (BooleanUtils.toBoolean(value.value)) {
|
||||
|
|
|
@ -34,7 +34,7 @@ public class HideToolbarDefaultRule implements ValueChangeRule {
|
|||
@Override
|
||||
public void applyRule(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribut,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
if (BooleanUtils.toBoolean(value.value)) {
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* 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.examconfig.impl.rules;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.BooleanUtils;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.ValueChangeRule;
|
||||
import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
@GuiProfile
|
||||
public class ProxyPasswordRule implements ValueChangeRule {
|
||||
|
||||
public static final String KEY_HTTP_PWD_REQUIRED = "HTTPRequiresPassword";
|
||||
|
||||
private final Map<String, Tuple<String>> observed;
|
||||
|
||||
public ProxyPasswordRule() {
|
||||
this.observed = new HashMap<>();
|
||||
this.observed.put(KEY_HTTP_PWD_REQUIRED, new Tuple<>("HTTPUsername", "HTTPPassword"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean observesAttribute(final ConfigurationAttribute attribute) {
|
||||
return this.observed.containsKey(attribute.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyRule(
|
||||
final ViewContext context,
|
||||
final ConfigurationAttribute attribute,
|
||||
final ConfigurationValue value) {
|
||||
|
||||
final Tuple<String> tuple = this.observed.get(attribute.name);
|
||||
if (tuple != null) {
|
||||
if (BooleanUtils.toBoolean(value.value)) {
|
||||
context.enable(tuple._1);
|
||||
context.enable(tuple._2);
|
||||
} else {
|
||||
context.disable(tuple._1);
|
||||
context.disable(tuple._2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -94,4 +94,6 @@ public interface I18nSupport {
|
|||
* @return the text in current language parsed from localized text */
|
||||
String getText(String key, Locale locale, String def, Object... args);
|
||||
|
||||
boolean hasText(LocTextKey locTooltipKey);
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
|||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||
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.auth.CurrentUser;
|
||||
|
||||
@Lazy
|
||||
|
@ -168,4 +169,13 @@ public class I18nSupportImpl implements I18nSupport {
|
|||
return this.messageSource.getMessage(key, args, def, locale);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasText(final LocTextKey key) {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return getText(key.name, (String) null) != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -155,7 +155,7 @@ public final class PolyglotPageServiceImpl implements PolyglotPageService {
|
|||
tableColumn.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
tableColumn.setText(this.i18nSupport.getText(locTextKey));
|
||||
|
||||
if (locTooltipKey != null) {
|
||||
if (this.i18nSupport.hasText(locTooltipKey)) {
|
||||
tableColumn.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey);
|
||||
tableColumn.setToolTipText(this.i18nSupport.getText(locTooltipKey));
|
||||
}
|
||||
|
@ -178,7 +178,7 @@ public final class PolyglotPageServiceImpl implements PolyglotPageService {
|
|||
tabItem.setData(POLYGLOT_ITEM_TEXT_DATA_KEY, locTextKey);
|
||||
tabItem.setText(this.i18nSupport.getText(locTextKey));
|
||||
|
||||
if (locTooltipKey != null) {
|
||||
if (this.i18nSupport.hasText(locTooltipKey)) {
|
||||
tabItem.setData(POLYGLOT_ITEM_TOOLTIP_DATA_KEY, locTooltipKey);
|
||||
tabItem.setToolTipText(this.i18nSupport.getText(locTooltipKey));
|
||||
}
|
||||
|
|
|
@ -189,7 +189,7 @@ public class PageServiceImpl implements PageService {
|
|||
.getUISession()
|
||||
.getHttpSession();
|
||||
|
||||
log.debug("SET session PageState: {} : {}", pageAction.definition.targetState, httpSession.getId());
|
||||
log.debug("Set session PageState: {} : {}", pageAction.definition.targetState, httpSession.getId());
|
||||
httpSession.setAttribute(ATTR_PAGE_STATE, pageAction.definition.targetState);
|
||||
|
||||
} catch (final Exception e) {
|
||||
|
|
|
@ -308,7 +308,8 @@ public class EntityTable<ROW extends Entity> {
|
|||
// TODO error handling
|
||||
});
|
||||
|
||||
this.composite.layout(true, true);
|
||||
this.composite.getParent().layout(true, true);
|
||||
PageService.updateScrolledComposite(this.composite);
|
||||
}
|
||||
|
||||
private Page<ROW> createTableRowsFromPage(final Page<ROW> page) {
|
||||
|
|
|
@ -33,6 +33,8 @@ public final class ColorSelection extends Composite implements Selection {
|
|||
private static final long serialVersionUID = 4775375044147842526L;
|
||||
private static final Logger log = LoggerFactory.getLogger(ColorSelection.class);
|
||||
|
||||
private static final LocTextKey DEFAULT_SELECT_TOOLTIP_KEY = new LocTextKey("sebserver.overall.action.select");
|
||||
|
||||
private static final int ACTION_COLUMN_WIDTH = 20;
|
||||
private final ColorDialog colorDialog;
|
||||
private final Composite colorField;
|
||||
|
@ -40,7 +42,11 @@ public final class ColorSelection extends Composite implements Selection {
|
|||
|
||||
private Listener listener = null;
|
||||
|
||||
ColorSelection(final Composite parent, final WidgetFactory widgetFactory) {
|
||||
ColorSelection(
|
||||
final Composite parent,
|
||||
final WidgetFactory widgetFactory,
|
||||
final String tooltipKeyPrefix) {
|
||||
|
||||
super(parent, SWT.NONE);
|
||||
final GridLayout gridLayout = new GridLayout(2, false);
|
||||
gridLayout.verticalSpacing = 1;
|
||||
|
@ -60,7 +66,9 @@ public final class ColorSelection extends Composite implements Selection {
|
|||
final Label imageButton = widgetFactory.imageButton(
|
||||
ImageIcon.COLOR,
|
||||
this,
|
||||
new LocTextKey("Set Color"),
|
||||
(StringUtils.isNoneBlank(tooltipKeyPrefix)
|
||||
? new LocTextKey(tooltipKeyPrefix)
|
||||
: DEFAULT_SELECT_TOOLTIP_KEY),
|
||||
this::addColorSelection);
|
||||
|
||||
final GridData actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
||||
|
|
|
@ -41,6 +41,9 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
|||
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 Combo combo;
|
||||
private final LocTextKey addTextKey;
|
||||
|
@ -64,10 +67,10 @@ public final class MultiSelectionCombo extends Composite implements Selection {
|
|||
this.widgetFactory = widgetFactory;
|
||||
this.addTextKey = (locTextPrefix != null)
|
||||
? new LocTextKey(locTextPrefix + ".add")
|
||||
: new LocTextKey("sebserver.overall.add");
|
||||
: DEFAULT_ADD_TOOLTIP_KEY;
|
||||
this.removeTextKey = (locTextPrefix != null)
|
||||
? new LocTextKey(locTextPrefix + ".remove")
|
||||
: new LocTextKey("sebserver.overall.remove");
|
||||
: DEFAULT_REMOVE_TOOLTIP_KEY;
|
||||
|
||||
final GridLayout gridLayout = new GridLayout(2, false);
|
||||
gridLayout.verticalSpacing = 1;
|
||||
|
|
|
@ -36,10 +36,11 @@ public final class ThresholdList extends Composite {
|
|||
private static final long serialVersionUID = -2305091471607040280L;
|
||||
private static final int ACTION_COLUMN_WIDTH = 20;
|
||||
|
||||
private static final LocTextKey valueTextKey = new LocTextKey("sebserver.exam.indicator.thresholds.list.value");
|
||||
private static final LocTextKey colorTextKey = new LocTextKey("sebserver.exam.indicator.thresholds.list.color");
|
||||
private static final LocTextKey addTextKey = new LocTextKey("sebserver.exam.indicator.thresholds.list.add");
|
||||
private static final LocTextKey removeTextKey = new LocTextKey("sebserver.exam.indicator.thresholds.list.remove");
|
||||
private static final String COLOR_SELECTION_TEXT_KEY = "sebserver.exam.indicator.thresholds.select.color";
|
||||
private static final LocTextKey VALUE_TEXT_KEY = new LocTextKey("sebserver.exam.indicator.thresholds.list.value");
|
||||
private static final LocTextKey COLOR_TEXT_KEY = new LocTextKey("sebserver.exam.indicator.thresholds.list.color");
|
||||
private static final LocTextKey ADD_TEXT_KEY = new LocTextKey("sebserver.exam.indicator.thresholds.list.add");
|
||||
private static final LocTextKey REMOVE_TEXT_KEY = new LocTextKey("sebserver.exam.indicator.thresholds.list.remove");
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final List<Entry> thresholds = new ArrayList<>();
|
||||
|
@ -62,18 +63,24 @@ public final class ThresholdList extends Composite {
|
|||
|
||||
this.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||
|
||||
final Label valueTitle = widgetFactory.labelLocalized(this, CustomVariant.TITLE_LABEL, valueTextKey);
|
||||
final Label valueTitle = widgetFactory.labelLocalized(
|
||||
this,
|
||||
CustomVariant.TITLE_LABEL,
|
||||
VALUE_TEXT_KEY);
|
||||
this.valueCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
valueTitle.setLayoutData(this.valueCell);
|
||||
|
||||
final Label colorTitle = widgetFactory.labelLocalized(this, CustomVariant.TITLE_LABEL, colorTextKey);
|
||||
final Label colorTitle = widgetFactory.labelLocalized(
|
||||
this,
|
||||
CustomVariant.TITLE_LABEL,
|
||||
COLOR_TEXT_KEY);
|
||||
this.colorCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
colorTitle.setLayoutData(this.colorCell);
|
||||
|
||||
final Label imageButton = widgetFactory.imageButton(
|
||||
ImageIcon.ADD_BOX,
|
||||
this,
|
||||
addTextKey,
|
||||
ADD_TEXT_KEY,
|
||||
this::addThreshold);
|
||||
this.actionCell = new GridData(SWT.LEFT, SWT.CENTER, true, false);
|
||||
imageButton.setLayoutData(this.actionCell);
|
||||
|
@ -120,7 +127,9 @@ public final class ThresholdList extends Composite {
|
|||
final GridData valueCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
valueInput.setLayoutData(valueCell);
|
||||
|
||||
final Selection selector = this.widgetFactory.selectionLocalized(Type.COLOR, this, null);
|
||||
final Selection selector = this.widgetFactory.selectionLocalized(
|
||||
Type.COLOR, this, null, null, null,
|
||||
COLOR_SELECTION_TEXT_KEY);
|
||||
final GridData selectorCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
selectorCell.horizontalIndent = 2;
|
||||
selector.adaptToControl().setLayoutData(selectorCell);
|
||||
|
@ -128,7 +137,7 @@ public final class ThresholdList extends Composite {
|
|||
final Label imageButton = this.widgetFactory.imageButton(
|
||||
ImageIcon.REMOVE_BOX,
|
||||
this,
|
||||
removeTextKey,
|
||||
REMOVE_TEXT_KEY,
|
||||
null);
|
||||
final GridData actionCell = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
imageButton.setLayoutData(actionCell);
|
||||
|
|
|
@ -281,7 +281,8 @@ public class WidgetFactory {
|
|||
}
|
||||
|
||||
public Text textAreaInput(final Composite content) {
|
||||
return new Text(content, SWT.LEFT | SWT.BORDER | SWT.MULTI);
|
||||
final Text textArea = new Text(content, SWT.LEFT | SWT.BORDER | SWT.MULTI);
|
||||
return textArea;
|
||||
}
|
||||
|
||||
public Text textInput(final Composite content, final boolean password) {
|
||||
|
@ -477,7 +478,7 @@ public class WidgetFactory {
|
|||
selection = new MultiSelectionCheckbox(parent);
|
||||
break;
|
||||
case COLOR:
|
||||
selection = new ColorSelection(parent, this);
|
||||
selection = new ColorSelection(parent, this, actionLocTextPrefix);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported Selection.Type: " + type);
|
||||
|
|
|
@ -230,12 +230,6 @@ public class PaginationServiceImpl implements PaginationService {
|
|||
|
||||
// Exam Table
|
||||
final Map<String, String> examTableMap = new HashMap<>();
|
||||
examTableMap.put(
|
||||
Domain.EXAM.ATTR_INSTITUTION_ID,
|
||||
ExamRecordDynamicSqlSupport.institutionId.name());
|
||||
examTableMap.put(
|
||||
Domain.EXAM.ATTR_LMS_SETUP_ID,
|
||||
ExamRecordDynamicSqlSupport.lmsSetupId.name());
|
||||
examTableMap.put(
|
||||
Domain.EXAM.ATTR_TYPE,
|
||||
ExamRecordDynamicSqlSupport.type.name());
|
||||
|
|
|
@ -210,6 +210,7 @@ public class ConfigurationDAOImpl implements ConfigurationDAO {
|
|||
|
||||
// with the current attribute values
|
||||
// TODO batch here for better performance
|
||||
// http://pretius.com/how-to-use-mybatis-effectively-perform-batch-db-operations/
|
||||
allValues.stream()
|
||||
.map(oldValRec -> new ConfigurationValueRecord(
|
||||
null,
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException;
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
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.ConfigurationNode.ConfigurationStatus;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode.ConfigurationType;
|
||||
|
@ -44,6 +45,7 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationReco
|
|||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationValueRecordDynamicSqlSupport;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ConfigurationValueRecordMapper;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ConfigurationAttributeRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ConfigurationNodeRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ConfigurationRecord;
|
||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.model.ConfigurationValueRecord;
|
||||
|
@ -361,6 +363,8 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
|||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
// filter child attributes of tables. No default value for tables. Use templates for that
|
||||
.filter(ConfigurationNodeDAOImpl::filterChildAttribute)
|
||||
.forEach(attrRec -> {
|
||||
final String value = templateValues.getOrDefault(
|
||||
attrRec.getId(),
|
||||
|
@ -379,6 +383,17 @@ public class ConfigurationNodeDAOImpl implements ConfigurationNodeDAO {
|
|||
});
|
||||
}
|
||||
|
||||
private static boolean filterChildAttribute(final ConfigurationAttributeRecord rec) {
|
||||
|
||||
if (rec.getParentId() == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return BooleanUtils.toBoolean(ConfigurationAttribute.getDependencyValue(
|
||||
ConfigurationAttribute.DEPENDENCY_CREATE_DEFAULT_VALUE,
|
||||
rec.getDependencies()));
|
||||
}
|
||||
|
||||
/*
|
||||
* Get values from template with configuration attribute id mapped to the value
|
||||
* returns empty list if no template available
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.springframework.stereotype.Component;
|
|||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.AttributeType;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue;
|
||||
|
@ -293,50 +294,109 @@ public class ConfigurationValueDAOImpl implements ConfigurationValueDAO {
|
|||
.flatMap(val -> attributeRecordById(val.attributeId))
|
||||
.map(attributeRecord -> {
|
||||
|
||||
final Map<Long, ConfigurationAttributeRecord> attributeMap = this.configurationAttributeRecordMapper
|
||||
.selectByExample()
|
||||
.where(
|
||||
ConfigurationAttributeRecordDynamicSqlSupport.parentId,
|
||||
isEqualTo(attributeRecord.getId()))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(rec -> rec.getId(), Function.identity()));
|
||||
|
||||
final List<Long> columnAttributeIds = attributeMap.values()
|
||||
.stream()
|
||||
.map(a -> a.getId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// first delete all old values of this table
|
||||
this.configurationValueRecordMapper.deleteByExample()
|
||||
.where(
|
||||
ConfigurationValueRecordDynamicSqlSupport.configurationId,
|
||||
isEqualTo(value.configurationId))
|
||||
.and(
|
||||
ConfigurationValueRecordDynamicSqlSupport.configurationAttributeId,
|
||||
SqlBuilder.isIn(columnAttributeIds))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
// then add the new values
|
||||
for (final TableValue tableValue : value.values) {
|
||||
final ConfigurationAttributeRecord columnAttr = attributeMap.get(tableValue.attributeId);
|
||||
final ConfigurationValueRecord valueRecord = new ConfigurationValueRecord(
|
||||
null,
|
||||
value.institutionId,
|
||||
value.configurationId,
|
||||
columnAttr.getId(),
|
||||
tableValue.listIndex,
|
||||
tableValue.value);
|
||||
|
||||
this.configurationValueRecordMapper.insert(valueRecord);
|
||||
final String type = attributeRecord.getType();
|
||||
if (AttributeType.TABLE.name().equals(type)) {
|
||||
saveAsTable(value, attributeRecord);
|
||||
} else {
|
||||
saveAsComposite(value);
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
private void saveAsTable(
|
||||
final ConfigurationTableValues value,
|
||||
final ConfigurationAttributeRecord attributeRecord) {
|
||||
|
||||
final Map<Long, ConfigurationAttributeRecord> attributeMap =
|
||||
this.configurationAttributeRecordMapper
|
||||
.selectByExample()
|
||||
.where(
|
||||
ConfigurationAttributeRecordDynamicSqlSupport.parentId,
|
||||
isEqualTo(attributeRecord.getId()))
|
||||
.build()
|
||||
.execute()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(rec -> rec.getId(), Function.identity()));
|
||||
|
||||
final List<Long> columnAttributeIds = attributeMap.values()
|
||||
.stream()
|
||||
.map(a -> a.getId())
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// first delete all old values of this table
|
||||
this.configurationValueRecordMapper.deleteByExample()
|
||||
.where(
|
||||
ConfigurationValueRecordDynamicSqlSupport.configurationId,
|
||||
isEqualTo(value.configurationId))
|
||||
.and(
|
||||
ConfigurationValueRecordDynamicSqlSupport.configurationAttributeId,
|
||||
SqlBuilder.isIn(columnAttributeIds))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
// then add the new values
|
||||
// TODO optimize with batching
|
||||
for (final TableValue tableValue : value.values) {
|
||||
final ConfigurationAttributeRecord columnAttr = attributeMap.get(tableValue.attributeId);
|
||||
final ConfigurationValueRecord valueRecord = new ConfigurationValueRecord(
|
||||
null,
|
||||
value.institutionId,
|
||||
value.configurationId,
|
||||
columnAttr.getId(),
|
||||
tableValue.listIndex,
|
||||
tableValue.value);
|
||||
|
||||
this.configurationValueRecordMapper.insert(valueRecord);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveAsComposite(final ConfigurationTableValues value) {
|
||||
// TODO optimize with batching
|
||||
for (final TableValue tableValue : value.values) {
|
||||
|
||||
final List<Long> valuePK = this.configurationValueRecordMapper.selectIdsByExample()
|
||||
.where(
|
||||
ConfigurationValueRecordDynamicSqlSupport.configurationId,
|
||||
isEqualTo(value.configurationId))
|
||||
.and(
|
||||
ConfigurationValueRecordDynamicSqlSupport.configurationAttributeId,
|
||||
isEqualTo(tableValue.attributeId))
|
||||
.and(
|
||||
ConfigurationValueRecordDynamicSqlSupport.listIndex,
|
||||
isEqualTo(tableValue.listIndex))
|
||||
.build()
|
||||
.execute();
|
||||
|
||||
if (valuePK != null && valuePK.size() > 1) {
|
||||
throw new IllegalStateException("Expected no more then one element");
|
||||
}
|
||||
|
||||
if (valuePK == null || valuePK.isEmpty()) {
|
||||
// insert
|
||||
this.configurationValueRecordMapper.insert(
|
||||
new ConfigurationValueRecord(
|
||||
null,
|
||||
value.institutionId,
|
||||
value.configurationId,
|
||||
tableValue.attributeId,
|
||||
tableValue.listIndex,
|
||||
tableValue.value));
|
||||
} else {
|
||||
// update
|
||||
this.configurationValueRecordMapper.updateByPrimaryKey(
|
||||
new ConfigurationValueRecord(
|
||||
valuePK.iterator().next(),
|
||||
value.institutionId,
|
||||
value.configurationId,
|
||||
tableValue.attributeId,
|
||||
tableValue.listIndex,
|
||||
tableValue.value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Result<ConfigurationAttributeRecord> attributeRecord(final ConfigurationValue value) {
|
||||
return attributeRecordById(value.attributeId);
|
||||
}
|
||||
|
|
|
@ -16,39 +16,28 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
|
|||
public interface SebClientConfigService {
|
||||
|
||||
static String SEB_CLIENT_CONFIG_EXAMPLE_XML =
|
||||
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
|
||||
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
|
||||
"<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\r\n"
|
||||
+
|
||||
"<plist version=\"1.0\">" +
|
||||
"<dict>" +
|
||||
"<key>sebMode</key>" +
|
||||
"<integer>1</integer>" +
|
||||
"<key>sebServerFallback</key>" +
|
||||
"<true />" +
|
||||
"<key>sebServerURL</key>" +
|
||||
"<string>%s</string>" +
|
||||
"<key>sebServerConfiguration</key>" +
|
||||
"<array>" +
|
||||
"<dict>" +
|
||||
"<key>institution</key>" +
|
||||
"<string>%s</string>" +
|
||||
"<key>clientName</key>" +
|
||||
"<string>%s</string>" +
|
||||
"<key>clientSecret</key>" +
|
||||
"<string>%s</string>" +
|
||||
"<key>accessTokenEndpoint</key>" +
|
||||
"<string>%s</string>" +
|
||||
"<key>handshakeEndpoint</key>" +
|
||||
"<string>%s</string>" +
|
||||
"<key>examConfigEndpoint</key>" +
|
||||
"<string>%s</string>" +
|
||||
"<key>pingEndpoint</key>" +
|
||||
"<string>%s</string>" +
|
||||
"<key>eventEndpoint</key>" +
|
||||
"<string>%s</string>" +
|
||||
"</dict>" +
|
||||
"</array>" +
|
||||
"</dict>" +
|
||||
"<plist version=\"1.0\">\r\n" +
|
||||
" <dict>\r\n" +
|
||||
" <key>sebMode</key>\r\n" +
|
||||
" <integer>1</integer>\r\n" +
|
||||
" <key>sebServerFallback</key>\r\n" +
|
||||
" <true />\r\n" +
|
||||
" <key>sebServerURL</key>\r\n" +
|
||||
" <string>%s</string>\r\n" +
|
||||
" <key>sebServerConfiguration</key>\r\n" +
|
||||
" <dict>\r\n" +
|
||||
" <key>institution</key>\r\n" +
|
||||
" <string>%s</string>\r\n" +
|
||||
" <key>clientName</key>\r\n" +
|
||||
" <string>%s</string>\r\n" +
|
||||
" <key>clientSecret</key>\r\n" +
|
||||
" <string>%s</string>\r\n" +
|
||||
" <key>apiDiscovery</key>\r\n" +
|
||||
" <string>%s</string>\r\n" +
|
||||
" </dict>\r\n" +
|
||||
" </dict>\r\n" +
|
||||
"</plist>";
|
||||
|
||||
boolean hasSebClientConfigurationForInstitution(Long institutionId);
|
||||
|
|
|
@ -24,7 +24,6 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SebClientConfig;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||
|
@ -54,7 +53,6 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
|||
private final String httpScheme;
|
||||
private final String serverAddress;
|
||||
private final String serverPort;
|
||||
private final String sebClientAPIEndpoint;
|
||||
|
||||
protected SebClientConfigServiceImpl(
|
||||
final InstitutionDAO institutionDAO,
|
||||
|
@ -64,8 +62,7 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
|||
final ZipService zipService,
|
||||
@Value("${sebserver.webservice.http.scheme}") final String httpScheme,
|
||||
@Value("${server.address}") final String serverAddress,
|
||||
@Value("${server.port}") final String serverPort,
|
||||
@Value("${sebserver.webservice.api.exam.endpoint}") final String sebClientAPIEndpoint) {
|
||||
@Value("${server.port}") final String serverPort) {
|
||||
|
||||
this.institutionDAO = institutionDAO;
|
||||
this.sebClientConfigDAO = sebClientConfigDAO;
|
||||
|
@ -75,7 +72,6 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
|||
this.httpScheme = httpScheme;
|
||||
this.serverAddress = serverAddress;
|
||||
this.serverPort = serverPort;
|
||||
this.sebClientAPIEndpoint = sebClientAPIEndpoint;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -136,11 +132,7 @@ public class SebClientConfigServiceImpl implements SebClientConfigService {
|
|||
String.valueOf(config.institutionId),
|
||||
plainClientId,
|
||||
plainClientSecret,
|
||||
API.OAUTH_TOKEN_ENDPOINT,
|
||||
this.sebClientAPIEndpoint + API.EXAM_API_HANDSHAKE_ENDPOINT,
|
||||
this.sebClientAPIEndpoint + API.EXAM_API_CONFIGURATION_REQUEST_ENDPOINT,
|
||||
this.sebClientAPIEndpoint + API.EXAM_API_PING_ENDPOINT,
|
||||
this.sebClientAPIEndpoint + API.EXAM_API_EVENT_ENDPOINT);
|
||||
"TODO:/exam-api/discovery");
|
||||
|
||||
PipedOutputStream pOut = null;
|
||||
PipedInputStream pIn = null;
|
||||
|
|
|
@ -27,9 +27,9 @@ 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.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.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain.EXAM;
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
|
@ -140,11 +140,16 @@ public class ExamAdministrationController extends ActivatableEntityController<Ex
|
|||
Collections.reverse(exams);
|
||||
}
|
||||
|
||||
final int start = (pageNum - 1) * pSize;
|
||||
int end = start + pageSize;
|
||||
if (exams.size() < end) {
|
||||
end = exams.size();
|
||||
}
|
||||
return new Page<>(
|
||||
exams.size() / pSize,
|
||||
pageNum,
|
||||
sort,
|
||||
exams.subList(pageNum * pSize, pageNum * pSize + pSize));
|
||||
exams.subList(start, end));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ server.servlet.context-path=/
|
|||
|
||||
spring.datasource.initialize=true
|
||||
spring.datasource.initialization-mode=always
|
||||
spring.datasource.url=jdbc:mariadb://localhost:6603/SEBServer?useSSL=false&createDatabaseIfNotExist=true&default-character-set=utf8mb4
|
||||
spring.datasource.url=jdbc:mariadb://localhost:6603/SEBServer?useSSL=false
|
||||
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
|
||||
spring.datasource.platform=dev
|
||||
spring.datasource.hikari.max-lifetime=600000
|
||||
|
|
|
@ -23,6 +23,7 @@ sebserver.overall.status.inactive=Inactive
|
|||
|
||||
sebserver.overall.action.add=Add;
|
||||
sebserver.overall.action.remove=Remove
|
||||
sebserver.overall.action.select=Please Select
|
||||
|
||||
################################
|
||||
# Form validation and messages
|
||||
|
@ -265,6 +266,7 @@ sebserver.exam.form.endtime=End Time
|
|||
sebserver.exam.form.status=Status
|
||||
sebserver.exam.form.type=Exam Type
|
||||
sebserver.exam.form.supporter=Exam Supporter
|
||||
sebserver.exam.form.supporter.add=Add as supporter for this exam
|
||||
|
||||
sebserver.exam.type.UNDEFINED=Not Defined
|
||||
sebserver.exam.type.MANAGED=Managed
|
||||
|
@ -319,7 +321,9 @@ sebserver.exam.indicator.form.exam=Exam
|
|||
sebserver.exam.indicator.form.name=Name
|
||||
sebserver.exam.indicator.form.type=Type
|
||||
sebserver.exam.indicator.form.color=Default Color
|
||||
sebserver.exam.indicator.form.color.action=Please select a color
|
||||
sebserver.exam.indicator.form.thresholds=Thresholds
|
||||
sebserver.exam.indicator.thresholds.select.color=Please select a color
|
||||
|
||||
sebserver.exam.indicator.thresholds.list.title=Thresholds
|
||||
sebserver.exam.indicator.thresholds.list.value=Value
|
||||
|
@ -570,7 +574,7 @@ sebserver.examconfig.props.label.allowSwitchToApplications=Allow switching to th
|
|||
sebserver.examconfig.props.label.allowFlashFullscreen=Allow Flash to switch to fullscreen mode (Mac)
|
||||
sebserver.examconfig.props.label.permittedProcesses.row.title=Permitted Processes
|
||||
sebserver.examconfig.props.label.permittedProcesses=Permitted Processes
|
||||
sebserver.examconfig.props.label.permittedProcesses.active=Activity
|
||||
sebserver.examconfig.props.label.permittedProcesses.active=Active
|
||||
sebserver.examconfig.props.label.permittedProcesses.os=OS
|
||||
sebserver.examconfig.props.label.permittedProcesses.os.0=Win
|
||||
sebserver.examconfig.props.label.permittedProcesses.os.1=OS X
|
||||
|
@ -594,7 +598,7 @@ sebserver.examconfig.props.label.permittedProcesses.strongKill=Force quit (risk
|
|||
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.row.title=Prohibited Processes
|
||||
sebserver.examconfig.props.label.prohibitedProcesses=Prohibited Processes
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.active=Activity
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.active=Active
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.os=OS
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.os.0=Win
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.os.1=OS X
|
||||
|
@ -604,16 +608,80 @@ sebserver.examconfig.props.label.prohibitedProcesses.originalName=Original Name
|
|||
sebserver.examconfig.props.label.prohibitedProcesses.identifier=Identifier
|
||||
sebserver.examconfig.props.label.prohibitedProcesses.strongKill=Force quit (risk of data loss)
|
||||
|
||||
sebserver.examconfig.props.group.urlFilter=Fitler
|
||||
sebserver.examconfig.props.label.URLFilterEnable=Activate URL Filtering
|
||||
sebserver.examconfig.props.label.URLFilterEnableContentFilter=Filter also embedded content
|
||||
sebserver.examconfig.props.label.URLFilterRules=Filter
|
||||
sebserver.examconfig.props.label.URLFilterRules.active=Activity
|
||||
sebserver.examconfig.props.label.URLFilterRules.row.title=URL Filter
|
||||
sebserver.examconfig.props.label.URLFilterRules.active=Active
|
||||
sebserver.examconfig.props.label.URLFilterRules.regex=Regex
|
||||
sebserver.examconfig.props.label.URLFilterRules.expression=Expression
|
||||
sebserver.examconfig.props.label.URLFilterRules.action=Action
|
||||
sebserver.examconfig.props.label.URLFilterRules.action.0=Block
|
||||
sebserver.examconfig.props.label.URLFilterRules.action.1=Allow
|
||||
|
||||
sebserver.examconfig.props.group.proxies=Proxies
|
||||
sebserver.examconfig.props.label.proxySettingsPolicy=proxy settings policy
|
||||
sebserver.examconfig.props.label.proxySettingsPolicy.0=Use system proxy setting
|
||||
sebserver.examconfig.props.label.proxySettingsPolicy.0.tooltip=System proxy settings of the exam client computer are used
|
||||
sebserver.examconfig.props.label.proxySettingsPolicy.1=Use SEB proxy settings
|
||||
sebserver.examconfig.props.label.proxySettingsPolicy.1.tooltip=Proxy settings provided in these SEB settings are used
|
||||
sebserver.examconfig.props.label.proxies=Double-click a protocol to configure:
|
||||
sebserver.examconfig.props.label.ExcludeSimpleHostnames=Exclude simple hostnames
|
||||
sebserver.examconfig.props.label.ExceptionsList=Bypass proxy settings for these hosts and domains
|
||||
sebserver.examconfig.props.label.ExceptionsList.tooltip=Separate hosts / domains with comma
|
||||
sebserver.examconfig.props.label.FTPPassive=Use Passive FTP Mode (PASV)
|
||||
|
||||
sebserver.examconfig.props.label.proxies.active=Active
|
||||
sebserver.examconfig.props.label.proxies.TABLE_ENTRY=Protocol
|
||||
sebserver.examconfig.props.label.autoDiscovery=Auto Proxy Discovery
|
||||
sebserver.examconfig.props.label.AutoDiscoveryEnabled=Auto discovery enabled
|
||||
sebserver.examconfig.props.label.autoConfiguration=Automatic Proxy Configuration
|
||||
sebserver.examconfig.props.label.AutoConfigurationEnabled=Auto configuration enabeld
|
||||
sebserver.examconfig.props.label.AutoConfigurationURL=Proxy configuration file URL
|
||||
sebserver.examconfig.props.label.AutoConfigurationJavaScript=Proxy configuration JavaScript
|
||||
|
||||
sebserver.examconfig.props.label.http=Web Proxy (HTTP)
|
||||
sebserver.examconfig.props.label.HTTPEnable=Web proxy eneabled
|
||||
sebserver.examconfig.props.label.HTTPProxy=Web proxy server
|
||||
sebserver.examconfig.props.label.HTTPPort=Web proxy port
|
||||
sebserver.examconfig.props.label.HTTPRequiresPassword=Proxy server requires password
|
||||
sebserver.examconfig.props.label.HTTPUsername=Username
|
||||
sebserver.examconfig.props.label.HTTPPassword=Password
|
||||
|
||||
sebserver.examconfig.props.label.https=Secure Web Proxy (HTTPS)
|
||||
sebserver.examconfig.props.label.HTTPSEnable=Secure web proxy eneabled
|
||||
sebserver.examconfig.props.label.HTTPSProxy=Secure web proxy server
|
||||
sebserver.examconfig.props.label.HTTPSPort=Secure web proxy port
|
||||
sebserver.examconfig.props.label.HTTPSRequiresPassword=Proxy server requires password
|
||||
sebserver.examconfig.props.label.HTTPSUsername=Username
|
||||
sebserver.examconfig.props.label.HTTPSPassword=Password
|
||||
|
||||
sebserver.examconfig.props.label.ftp=FTP Proxy
|
||||
sebserver.examconfig.props.label.FTPEnable=FTP proxy eneabled
|
||||
sebserver.examconfig.props.label.FTPProxy=FTP proxy server
|
||||
sebserver.examconfig.props.label.FTPPort=FTP proxy port
|
||||
sebserver.examconfig.props.label.FTPRequiresPassword=Proxy server requires password
|
||||
sebserver.examconfig.props.label.FTPUsername=Username
|
||||
sebserver.examconfig.props.label.FTPPassword=Password
|
||||
|
||||
sebserver.examconfig.props.label.socks=SOCKS Proxy
|
||||
sebserver.examconfig.props.label.SOCKSEnable=SOCKS proxy eneabled
|
||||
sebserver.examconfig.props.label.SOCKSProxy=SOCKS proxy server
|
||||
sebserver.examconfig.props.label.SOCKSPort=SOCKS proxy port
|
||||
sebserver.examconfig.props.label.SOCKSRequiresPassword=Proxy server requires password
|
||||
sebserver.examconfig.props.label.SOCKSUsername=Username
|
||||
sebserver.examconfig.props.label.SOCKSPassword=Password
|
||||
|
||||
sebserver.examconfig.props.label.rtsp=Streaming Proxy (RTSP)
|
||||
sebserver.examconfig.props.label.RTSPEnable=RTSP proxy eneabled
|
||||
sebserver.examconfig.props.label.RTSPProxy=RTSP proxy server
|
||||
sebserver.examconfig.props.label.RTSPPort=RTSP proxy port
|
||||
sebserver.examconfig.props.label.RTSPRequiresPassword=Proxy server requires password
|
||||
sebserver.examconfig.props.label.RTSPUsername=Username
|
||||
sebserver.examconfig.props.label.RTSPPassword=Password
|
||||
|
||||
|
||||
sebserver.examconfig.props.group.servicePolicy=SEB Service policy
|
||||
sebserver.examconfig.props.label.sebServicePolicy.0=allow to run SEB without service
|
||||
sebserver.examconfig.props.label.sebServicePolicy.1=display warning when service is not running
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
-- MySQL Script generated by MySQL Workbench
|
||||
-- Fri May 24 11:57:07 2019
|
||||
-- Wed May 29 15:30:50 2019
|
||||
-- Model: New Model Version: 1.0
|
||||
-- MySQL Workbench Forward Engineering
|
||||
|
||||
|
@ -10,13 +10,20 @@ SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
|
|||
-- -----------------------------------------------------
|
||||
-- Schema SEBServer
|
||||
-- -----------------------------------------------------
|
||||
DROP SCHEMA IF EXISTS `SEBServer` ;
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `institution`
|
||||
-- Schema SEBServer
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `institution` ;
|
||||
CREATE SCHEMA IF NOT EXISTS `SEBServer` DEFAULT CHARACTER SET utf8mb4 ;
|
||||
USE `SEBServer` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `institution` (
|
||||
-- -----------------------------------------------------
|
||||
-- Table `SEBServer`.`institution`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `SEBServer`.`institution` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`institution` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
`url_suffix` VARCHAR(45) NULL,
|
||||
|
@ -29,11 +36,11 @@ CREATE TABLE IF NOT EXISTS `institution` (
|
|||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `lms_setup`
|
||||
-- Table `SEBServer`.`lms_setup`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `lms_setup` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`lms_setup` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `lms_setup` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`lms_setup` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
|
@ -47,18 +54,18 @@ CREATE TABLE IF NOT EXISTS `lms_setup` (
|
|||
INDEX `setupInstitutionRef_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `setupInstitutionRef`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
REFERENCES `SEBServer`.`institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `exam`
|
||||
-- Table `SEBServer`.`exam`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `exam` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`exam` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `exam` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`exam` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||
`lms_setup_id` BIGINT UNSIGNED NOT NULL,
|
||||
|
@ -74,23 +81,23 @@ CREATE TABLE IF NOT EXISTS `exam` (
|
|||
INDEX `institution_key_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `examLmsSetupRef`
|
||||
FOREIGN KEY (`lms_setup_id`)
|
||||
REFERENCES `lms_setup` (`id`)
|
||||
REFERENCES `SEBServer`.`lms_setup` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `examInstitutionRef`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
REFERENCES `SEBServer`.`institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `client_connection`
|
||||
-- Table `SEBServer`.`client_connection`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `client_connection` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`client_connection` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `client_connection` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`client_connection` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`exam_id` BIGINT UNSIGNED NULL,
|
||||
`status` VARCHAR(45) NOT NULL,
|
||||
|
@ -103,18 +110,18 @@ CREATE TABLE IF NOT EXISTS `client_connection` (
|
|||
INDEX `connection_exam_ref_idx` (`exam_id` ASC),
|
||||
CONSTRAINT `clientConnectionExamRef`
|
||||
FOREIGN KEY (`exam_id`)
|
||||
REFERENCES `exam` (`id`)
|
||||
REFERENCES `SEBServer`.`exam` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `client_event`
|
||||
-- Table `SEBServer`.`client_event`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `client_event` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`client_event` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `client_event` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`client_event` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`connection_id` BIGINT UNSIGNED NOT NULL,
|
||||
`user_identifier` VARCHAR(255) NOT NULL,
|
||||
|
@ -126,18 +133,18 @@ CREATE TABLE IF NOT EXISTS `client_event` (
|
|||
INDEX `eventConnectionRef_idx` (`connection_id` ASC),
|
||||
CONSTRAINT `eventConnectionRef`
|
||||
FOREIGN KEY (`connection_id`)
|
||||
REFERENCES `client_connection` (`id`)
|
||||
REFERENCES `SEBServer`.`client_connection` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `indicator`
|
||||
-- Table `SEBServer`.`indicator`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `indicator` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`indicator` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `indicator` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`indicator` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`exam_id` BIGINT UNSIGNED NOT NULL,
|
||||
`type` VARCHAR(45) NOT NULL,
|
||||
|
@ -147,18 +154,18 @@ CREATE TABLE IF NOT EXISTS `indicator` (
|
|||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `exam_ref`
|
||||
FOREIGN KEY (`exam_id`)
|
||||
REFERENCES `exam` (`id`)
|
||||
REFERENCES `SEBServer`.`exam` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `configuration_node`
|
||||
-- Table `SEBServer`.`configuration_node`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `configuration_node` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`configuration_node` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `configuration_node` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`configuration_node` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||
`template_id` BIGINT UNSIGNED NULL,
|
||||
|
@ -171,18 +178,18 @@ CREATE TABLE IF NOT EXISTS `configuration_node` (
|
|||
INDEX `configurationInstitutionRef_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configurationInstitutionRef`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
REFERENCES `SEBServer`.`institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `configuration`
|
||||
-- Table `SEBServer`.`configuration`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `configuration` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`configuration` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `configuration` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`configuration` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||
`configuration_node_id` BIGINT UNSIGNED NOT NULL,
|
||||
|
@ -194,23 +201,23 @@ CREATE TABLE IF NOT EXISTS `configuration` (
|
|||
INDEX `config_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configuration_node_ref`
|
||||
FOREIGN KEY (`configuration_node_id`)
|
||||
REFERENCES `configuration_node` (`id`)
|
||||
REFERENCES `SEBServer`.`configuration_node` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `config_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
REFERENCES `SEBServer`.`institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `configuration_attribute`
|
||||
-- Table `SEBServer`.`configuration_attribute`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `configuration_attribute` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`configuration_attribute` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `configuration_attribute` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`configuration_attribute` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(45) NOT NULL,
|
||||
`type` VARCHAR(45) NOT NULL,
|
||||
|
@ -223,52 +230,53 @@ CREATE TABLE IF NOT EXISTS `configuration_attribute` (
|
|||
INDEX `parent_ref_idx` (`parent_id` ASC),
|
||||
CONSTRAINT `parent_ref`
|
||||
FOREIGN KEY (`parent_id`)
|
||||
REFERENCES `configuration_attribute` (`id`)
|
||||
REFERENCES `SEBServer`.`configuration_attribute` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `configuration_value`
|
||||
-- Table `SEBServer`.`configuration_value`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `configuration_value` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`configuration_value` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `configuration_value` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`configuration_value` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||
`configuration_id` BIGINT UNSIGNED NOT NULL,
|
||||
`configuration_attribute_id` BIGINT UNSIGNED NOT NULL,
|
||||
`list_index` INT NOT NULL DEFAULT 0,
|
||||
`value` VARCHAR(20000) NULL,
|
||||
`value` VARCHAR(16000) NULL,
|
||||
`configuration_valuecol` VARCHAR(45) NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
INDEX `configuration_value_ref_idx` (`configuration_id` ASC),
|
||||
INDEX `configuration_attribute_ref_idx` (`configuration_attribute_id` ASC),
|
||||
INDEX `configuration_value_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `configuration_ref`
|
||||
FOREIGN KEY (`configuration_id`)
|
||||
REFERENCES `configuration` (`id`)
|
||||
REFERENCES `SEBServer`.`configuration` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_value_attribute_ref`
|
||||
FOREIGN KEY (`configuration_attribute_id`)
|
||||
REFERENCES `configuration_attribute` (`id`)
|
||||
REFERENCES `SEBServer`.`configuration_attribute` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_value_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
REFERENCES `SEBServer`.`institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `view`
|
||||
-- Table `SEBServer`.`view`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `view` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`view` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `view` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`view` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`name` VARCHAR(255) NULL,
|
||||
`columns` INT NOT NULL,
|
||||
|
@ -278,11 +286,11 @@ CREATE TABLE IF NOT EXISTS `view` (
|
|||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `orientation`
|
||||
-- Table `SEBServer`.`orientation`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `orientation` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`orientation` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `orientation` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`orientation` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`config_attribute_id` BIGINT UNSIGNED NOT NULL,
|
||||
`template_id` BIGINT UNSIGNED NULL,
|
||||
|
@ -298,23 +306,23 @@ CREATE TABLE IF NOT EXISTS `orientation` (
|
|||
INDEX `orientation_view_ref_idx` (`view_id` ASC),
|
||||
CONSTRAINT `config_attribute_orientation_ref`
|
||||
FOREIGN KEY (`config_attribute_id`)
|
||||
REFERENCES `configuration_attribute` (`id`)
|
||||
REFERENCES `SEBServer`.`configuration_attribute` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `orientation_view_ref`
|
||||
FOREIGN KEY (`view_id`)
|
||||
REFERENCES `view` (`id`)
|
||||
REFERENCES `SEBServer`.`view` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `exam_configuration_map`
|
||||
-- Table `SEBServer`.`exam_configuration_map`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `exam_configuration_map` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`exam_configuration_map` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `exam_configuration_map` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`exam_configuration_map` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||
`exam_id` BIGINT UNSIGNED NOT NULL,
|
||||
|
@ -327,28 +335,28 @@ CREATE TABLE IF NOT EXISTS `exam_configuration_map` (
|
|||
INDEX `exam_config_institution_ref_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `exam_map_ref`
|
||||
FOREIGN KEY (`exam_id`)
|
||||
REFERENCES `exam` (`id`)
|
||||
REFERENCES `SEBServer`.`exam` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `configuration_map_ref`
|
||||
FOREIGN KEY (`configuration_node_id`)
|
||||
REFERENCES `configuration_node` (`id`)
|
||||
REFERENCES `SEBServer`.`configuration_node` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION,
|
||||
CONSTRAINT `exam_config_institution_ref`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
REFERENCES `SEBServer`.`institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `user`
|
||||
-- Table `SEBServer`.`user`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `user` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`user` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `user` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`user` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||
`uuid` VARCHAR(255) NOT NULL,
|
||||
|
@ -363,18 +371,18 @@ CREATE TABLE IF NOT EXISTS `user` (
|
|||
INDEX `institutionRef_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `userInstitutionRef`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
REFERENCES `SEBServer`.`institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `user_role`
|
||||
-- Table `SEBServer`.`user_role`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `user_role` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`user_role` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `user_role` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`user_role` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_id` BIGINT UNSIGNED NOT NULL,
|
||||
`role_name` VARCHAR(45) NOT NULL,
|
||||
|
@ -382,18 +390,18 @@ CREATE TABLE IF NOT EXISTS `user_role` (
|
|||
INDEX `user_ref_idx` (`user_id` ASC),
|
||||
CONSTRAINT `user_ref`
|
||||
FOREIGN KEY (`user_id`)
|
||||
REFERENCES `user` (`id`)
|
||||
REFERENCES `SEBServer`.`user` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `oauth_access_token`
|
||||
-- Table `SEBServer`.`oauth_access_token`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `oauth_access_token` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`oauth_access_token` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `oauth_access_token` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`oauth_access_token` (
|
||||
`token_id` VARCHAR(255) NULL,
|
||||
`token` BLOB NULL,
|
||||
`authentication_id` VARCHAR(255) NULL,
|
||||
|
@ -405,11 +413,11 @@ CREATE TABLE IF NOT EXISTS `oauth_access_token` (
|
|||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `oauth_refresh_token`
|
||||
-- Table `SEBServer`.`oauth_refresh_token`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `oauth_refresh_token` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`oauth_refresh_token` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `oauth_refresh_token` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`oauth_refresh_token` (
|
||||
`token_id` VARCHAR(255) NULL,
|
||||
`token` BLOB NULL,
|
||||
`authentication` BLOB NULL)
|
||||
|
@ -417,11 +425,11 @@ CREATE TABLE IF NOT EXISTS `oauth_refresh_token` (
|
|||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `threshold`
|
||||
-- Table `SEBServer`.`threshold`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `threshold` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`threshold` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `threshold` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`threshold` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`indicator_id` BIGINT UNSIGNED NOT NULL,
|
||||
`value` DECIMAL(10,4) NOT NULL,
|
||||
|
@ -430,18 +438,18 @@ CREATE TABLE IF NOT EXISTS `threshold` (
|
|||
INDEX `indicator_threshold_id_idx` (`indicator_id` ASC),
|
||||
CONSTRAINT `indicator_threshold_id`
|
||||
FOREIGN KEY (`indicator_id`)
|
||||
REFERENCES `indicator` (`id`)
|
||||
REFERENCES `SEBServer`.`indicator` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `user_activity_log`
|
||||
-- Table `SEBServer`.`user_activity_log`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `user_activity_log` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`user_activity_log` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `user_activity_log` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`user_activity_log` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`user_uuid` VARCHAR(255) NOT NULL,
|
||||
`timestamp` BIGINT NOT NULL,
|
||||
|
@ -454,11 +462,11 @@ CREATE TABLE IF NOT EXISTS `user_activity_log` (
|
|||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `additional_attributes`
|
||||
-- Table `SEBServer`.`additional_attributes`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `additional_attributes` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`additional_attributes` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `additional_attributes` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`additional_attributes` (
|
||||
`id` BIGINT UNSIGNED NOT NULL,
|
||||
`entity_type` VARCHAR(45) NOT NULL,
|
||||
`entity_id` BIGINT UNSIGNED NOT NULL,
|
||||
|
@ -469,11 +477,11 @@ CREATE TABLE IF NOT EXISTS `additional_attributes` (
|
|||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `seb_client_configuration`
|
||||
-- Table `SEBServer`.`seb_client_configuration`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `seb_client_configuration` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`seb_client_configuration` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `seb_client_configuration` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`seb_client_configuration` (
|
||||
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`institution_id` BIGINT UNSIGNED NOT NULL,
|
||||
`name` VARCHAR(255) NOT NULL,
|
||||
|
@ -486,18 +494,18 @@ CREATE TABLE IF NOT EXISTS `seb_client_configuration` (
|
|||
INDEX `sebClientCredentialsInstitutionRef_idx` (`institution_id` ASC),
|
||||
CONSTRAINT `sebClientConfigInstitutionRef`
|
||||
FOREIGN KEY (`institution_id`)
|
||||
REFERENCES `institution` (`id`)
|
||||
REFERENCES `SEBServer`.`institution` (`id`)
|
||||
ON DELETE NO ACTION
|
||||
ON UPDATE NO ACTION)
|
||||
;
|
||||
|
||||
|
||||
-- -----------------------------------------------------
|
||||
-- Table `webservice_server_info`
|
||||
-- Table `SEBServer`.`webservice_server_info`
|
||||
-- -----------------------------------------------------
|
||||
DROP TABLE IF EXISTS `webservice_server_info` ;
|
||||
DROP TABLE IF EXISTS `SEBServer`.`webservice_server_info` ;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `webservice_server_info` (
|
||||
CREATE TABLE IF NOT EXISTS `SEBServer`.`webservice_server_info` (
|
||||
`id` BIGINT UNSIGNED NOT NULL,
|
||||
`uuid` VARCHAR(255) NOT NULL,
|
||||
`service_address` VARCHAR(255) NOT NULL,
|
||||
|
|
|
@ -233,7 +233,7 @@ Text.error {
|
|||
|
||||
Text[MULTI] {
|
||||
padding: 5px 10px 5px 10px;
|
||||
height: 50px;
|
||||
height: 100px;
|
||||
}
|
||||
|
||||
Text[BORDER], Text[MULTI][BORDER] {
|
||||
|
@ -250,6 +250,7 @@ Text[BORDER]:focused, Text[MULTI][BORDER]:focused {
|
|||
Text[BORDER]:disabled, Text[MULTI][BORDER]:disabled, Text[BORDER]:read-only,
|
||||
Text[MULTI][BORDER]:read-only {
|
||||
box-shadow: none;
|
||||
color: #CFCFCF;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue