GUI improvements

This commit is contained in:
anhefti 2020-02-13 16:46:36 +01:00
parent 8ea0def877
commit 25485b1fd4
28 changed files with 7160 additions and 6921 deletions

View file

@ -25,6 +25,7 @@ public final class Constants {
public static final String DEFAULT_LANG_CODE = "en";
public static final String DEFAULT_TIME_ZONE_CODE = "UTC";
public static final String TOOLTIP_TEXT_KEY_SUFFIX = ".tooltip";
public static final int SEB_FILE_HEADER_SIZE = 4;
public static final int JN_CRYPTOR_ITERATIONS = 10000;

View file

@ -59,7 +59,7 @@ public final class UserInfo implements UserAccount, Serializable {
public final String uuid;
/** The foreign key identifier to the institution where the User belongs to */
@NotNull
@NotNull(message = "user:institutionId:notNull")
@JsonProperty(USER.ATTR_INSTITUTION_ID)
public final Long institutionId;
@ -68,11 +68,12 @@ public final class UserInfo implements UserAccount, Serializable {
/** First name of the user */
@NotNull(message = "user:name:notNull")
@Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
@Size(max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
@JsonProperty(USER.ATTR_NAME)
public final String name;
/** Surname of the user */
@NotNull(message = "user:surname:notNull")
@Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}")
@JsonProperty(USER.ATTR_SURNAME)
public final String surname;
@ -215,7 +216,7 @@ public final class UserInfo implements UserAccount, Serializable {
public EnumSet<UserRole> getUserRoles() {
return EnumSet.copyOf(
getRoles().stream()
.map(r -> UserRole.valueOf(r))
.map(UserRole::valueOf)
.collect(Collectors.toList()));
}
@ -300,7 +301,7 @@ public final class UserInfo implements UserAccount, Serializable {
*
* @param userInfo UserInfo instance to copy
* @return copied UserInfo instance */
public static final UserInfo of(final UserInfo userInfo) {
public static UserInfo of(final UserInfo userInfo) {
return new UserInfo(
userInfo.getUuid(),
userInfo.getInstitutionId(),
@ -326,7 +327,7 @@ public final class UserInfo implements UserAccount, Serializable {
* @param timeZone new timeZone or null if the timeZone of given userInfo should be taken
* @param roles new timeZone or null if the roles of given userInfo should be taken
* @return copied UserInfo instance with the given attributes */
public static final UserInfo of(
public static UserInfo of(
final UserInfo userInfo,
final String name,
final String username,
@ -350,11 +351,11 @@ public final class UserInfo implements UserAccount, Serializable {
(roles != null) ? new HashSet<>(Arrays.asList(roles)) : userInfo.roles);
}
public static final UserInfo withEMail(final UserInfo userInfo, final String email) {
public static UserInfo withEMail(final UserInfo userInfo, final String email) {
return of(userInfo, null, null, null, email, null, null, (String[]) null);
}
public static final UserInfo withRoles(final UserInfo userInfo, final String... roles) {
public static UserInfo withRoles(final UserInfo userInfo, final String... roles) {
return of(userInfo, null, null, null, null, null, null, roles);
}
}

View file

@ -49,11 +49,12 @@ public final class UserMod implements UserAccount {
/** first (or full) name of the user */
@NotNull(message = "user:name:notNull")
@Size(min = 3, max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
@Size(max = 255, message = "user:name:size:{min}:{max}:${validatedValue}")
@JsonProperty(USER.ATTR_NAME)
public final String name;
/** surname of the user */
@NotNull(message = "user:surname:notNull")
@Size(max = 255, message = "user:surname:size:{min}:{max}:${validatedValue}")
@JsonProperty(USER.ATTR_SURNAME)
public final String surname;

View file

@ -30,6 +30,15 @@ public class Tuple<T> {
return this._2;
}
@SuppressWarnings("unchecked")
public <TT extends Tuple<T>> TT adaptTo(Class<TT> type) {
if (type.equals(this.getClass())) {
return (TT) this;
}
return null;
}
@Override
public int hashCode() {
final int prime = 31;

View file

@ -0,0 +1,41 @@
/*
* Copyright (c) 2020 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gbl.util;
import java.util.Objects;
/** A tuple of three elements of the same type */
public class Tuple3<T> extends Tuple<T> {
/** The third element of the tuple */
public final T _3;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
Tuple3<?> tuple3 = (Tuple3<?>) o;
return Objects.equals(_3, tuple3._3);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), _3);
}
public Tuple3(T _1, T _2, T _3) {
super(_1, _2);
this._3 = _3;
}
public T get_3() {
return _3;
}
}

View file

@ -8,8 +8,9 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.Arrays;
import java.util.Collections;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
@ -68,6 +69,8 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
new LocTextKey("sebserver.configtemplate.attr.form.group");
private static final LocTextKey FORM_VALUE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attr.form.value");
private static final LocTextKey FORM_VALUE_TOOLTIP_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attr.form.value" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
private final PageService pageService;
private final RestService restService;
@ -164,11 +167,12 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
valSpace.setLayout(new GridLayout());
valSpace.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
widgetFactory.label(content, StringUtils.EMPTY);
widgetFactory.labelLocalized(
valSpace,
CustomVariant.TEXT_H2,
FORM_VALUE_TEXT_KEY);
CustomVariant.TEXT_H3,
FORM_VALUE_TEXT_KEY,
FORM_VALUE_TOOLTIP_TEXT_KEY);
widgetFactory.labelSeparator(valSpace);
final Composite grid = new Composite(valSpace, SWT.NONE);
@ -201,7 +205,7 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
this.examConfigurationService.initInputFieldValues(
configuration.id,
Arrays.asList(viewContext));
Collections.singletonList(viewContext));
this.pageService.pageActionBuilder(formContext.clearEntityKeys())

View file

@ -64,6 +64,8 @@ public class ConfigTemplateForm implements TemplateComposer {
new LocTextKey("sebserver.configtemplate.form.description");
private static final LocTextKey ATTRIBUTES_LIST_TITLE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.title");
private static final LocTextKey ATTRIBUTES_LIST_TITLE_TOOLTIP_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.title" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
private static final LocTextKey ATTRIBUTES_LIST_NAME_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.attrs.list.name");
private static final LocTextKey ATTRIBUTES_LIST_VIEW_TEXT_KEY =
@ -158,7 +160,8 @@ public class ConfigTemplateForm implements TemplateComposer {
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_NAME,
FORM_NAME_TEXT_KEY,
examConfig.name))
examConfig.name)
.mandatory(!isReadonly))
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_DESCRIPTION_TEXT_KEY,
@ -174,10 +177,13 @@ public class ConfigTemplateForm implements TemplateComposer {
if (isReadonly) {
widgetFactory.label(content, "");
widgetFactory.labelLocalizedTitle(
widgetFactory.label(content, StringUtils.EMPTY);
widgetFactory.labelLocalized(
content,
ATTRIBUTES_LIST_TITLE_TEXT_KEY);
WidgetFactory.CustomVariant.TEXT_H3,
ATTRIBUTES_LIST_TITLE_TEXT_KEY,
ATTRIBUTES_LIST_TITLE_TOOLTIP_TEXT_KEY);
widgetFactory.labelSeparator(content);
final TableFilterAttribute viewFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION,
@ -186,7 +192,7 @@ public class ConfigTemplateForm implements TemplateComposer {
final TableFilterAttribute typeFilter = new TableFilterAttribute(
CriteriaType.SINGLE_SELECTION,
TemplateAttribute.FILTER_ATTR_TYPE,
() -> this.resourceService.getAttributeTypeResources());
this.resourceService::getAttributeTypeResources);
final EntityTable<TemplateAttribute> attrTable =
this.pageService.entityTableBuilder(
@ -228,6 +234,14 @@ public class ConfigTemplateForm implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT)
.withParentEntityKey(entityKey)
.create())
.withSelectionListener(this.pageService.getSelectionPublisher(
pageContext,
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_EDIT,
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT,
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW,
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW))
.compose(pageContext.copyOf(content));
pageActionBuilder
@ -238,7 +252,7 @@ public class ConfigTemplateForm implements TemplateComposer {
attrTable::getSelection,
PageAction::applySingleSelectionAsEntityKey,
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.publishIf(() -> attrTable.hasAnyContent())
.publishIf(attrTable::hasAnyContent, false)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_SET_DEFAULT)
.withParentEntityKey(entityKey)
@ -247,7 +261,7 @@ public class ConfigTemplateForm implements TemplateComposer {
action -> this.resetToDefaults(action, attrTable),
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.noEventPropagation()
.publishIf(() -> attrTable.hasAnyContent())
.publishIf(attrTable::hasAnyContent, false)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_REMOVE_VIEW)
.withParentEntityKey(entityKey)
@ -256,7 +270,7 @@ public class ConfigTemplateForm implements TemplateComposer {
action -> this.removeFormView(action, attrTable),
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.noEventPropagation()
.publishIf(() -> attrTable.hasAnyContent())
.publishIf(attrTable::hasAnyContent, false)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_ATTR_LIST_ATTACH_DEFAULT_VIEW)
.withParentEntityKey(entityKey)
@ -265,7 +279,7 @@ public class ConfigTemplateForm implements TemplateComposer {
action -> this.attachView(action, attrTable),
EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY)
.noEventPropagation()
.publishIf(() -> attrTable.hasAnyContent());
.publishIf(attrTable::hasAnyContent, false);
}
pageActionBuilder
@ -315,7 +329,7 @@ public class ConfigTemplateForm implements TemplateComposer {
}
}
private final PageAction resetToDefaults(
private PageAction resetToDefaults(
final PageAction action,
final EntityTable<TemplateAttribute> attrTable) {
@ -325,7 +339,7 @@ public class ConfigTemplateForm implements TemplateComposer {
return resetToDefaults;
}
private final PageAction removeFormView(
private PageAction removeFormView(
final PageAction action,
final EntityTable<TemplateAttribute> attrTable) {
@ -335,7 +349,7 @@ public class ConfigTemplateForm implements TemplateComposer {
return removeFormView;
}
private final PageAction attachView(
private PageAction attachView(
final PageAction action,
final EntityTable<TemplateAttribute> attrTable) {

View file

@ -43,7 +43,7 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
@GuiProfile
public class ConfigTemplateList implements TemplateComposer {
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION =
private static final LocTextKey NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION =
new LocTextKey("sebserver.examconfig.list.action.no.modify.privilege");
private static final LocTextKey TITLE_TEMPLATE_TEXT_KEY =
new LocTextKey("sebserver.configtemplate.list.title");
@ -131,6 +131,12 @@ public class ConfigTemplateList implements TemplateComposer {
.withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
.create())
.withSelectionListener(this.pageService.getSelectionPublisher(
pageContext,
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST,
ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST))
.compose(pageContext.copyOf(content));
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
@ -142,14 +148,12 @@ public class ConfigTemplateList implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST)
.withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
.publishIf(() -> templateTable.hasAnyContent())
.publishIf(templateTable::hasAnyContent, false)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST)
.withSelect(
templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUTION),
PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent());
.publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent(), false);
}
}

View file

@ -20,7 +20,7 @@ import java.util.function.Function;
import java.util.function.Supplier;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.tomcat.util.buf.StringUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.swt.widgets.Composite;
@ -394,7 +394,7 @@ public class ExamForm implements TemplateComposer {
if (readonly && !importFromQuizData) {
// List of SEB Configuration
this.widgetFactory.label(content, "");
this.widgetFactory.label(content, StringUtils.EMPTY);
this.widgetFactory.labelLocalized(
content,
CustomVariant.TEXT_H3,

View file

@ -131,11 +131,6 @@ public class InstitutionForm implements TemplateComposer {
.newAction(ActionDefinition.INSTITUTION_NEW)
.publishIf(() -> writeGrant && isReadonly)
// Removed as discussed in SEBSERV-52
// .newAction(ActionDefinition.USER_ACCOUNT_NEW)
// .withParentEntityKey(entityKey)
// .publishIf(() -> userWriteGrant && isReadonly && institution.isActive())
.newAction(ActionDefinition.INSTITUTION_MODIFY)
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly)

View file

@ -140,7 +140,7 @@ public class InstitutionList implements TemplateComposer {
table::getSelection,
PageAction::applySingleSelectionAsEntityKey,
EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent(), false)
.publishIf(table::hasAnyContent, false)
.newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST)
.withSelect(

View file

@ -196,6 +196,12 @@ public class SebClientConfigForm implements TemplateComposer {
.ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly)
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_SAVE_AND_ACTIVATE)
.withEntityKey(entityKey)
.withExec(formHandle::saveAndActivate)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !isReadonly && !clientConfig.isActive())
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_CANCEL_MODIFY)
.withEntityKey(entityKey)
.withExec(this.pageService.backToCurrentFunction())

View file

@ -151,6 +151,16 @@ public class SebClientConfigList implements TemplateComposer {
.withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
.create())
.withSelectionListener(this.pageService.getSelectionPublisher(
ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY,
ActionDefinition.SEB_CLIENT_CONFIG_ACTIVATE,
ActionDefinition.SEB_CLIENT_CONFIG_DEACTIVATE,
pageContext,
ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST,
ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST,
ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY))
.compose(pageContext.copyOf(content));
final GrantCheck clientConfigGrant = this.currentUser.grantCheck(EntityType.SEB_CLIENT_CONFIGURATION);
@ -162,13 +172,20 @@ public class SebClientConfigList implements TemplateComposer {
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent())
.publishIf(table::hasAnyContent, false)
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST)
.withSelect(
table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent());
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false)
.newAction(ActionDefinition.SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY)
.withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY))
.withConfirm(this.pageService.confirmDeactivation(table))
.publishIf(() -> clientConfigGrant.im() && table.hasAnyContent(), false);
}

View file

@ -144,6 +144,12 @@ public class SebExamConfigList implements TemplateComposer {
.withDefaultAction(pageActionBuilder
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
.create())
.withSelectionListener(this.pageService.getSelectionPublisher(
pageContext,
ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST,
ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST))
.compose(pageContext.copyOf(content));
final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE);
@ -155,20 +161,18 @@ public class SebExamConfigList implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST)
.withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey,
EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> configTable.hasAnyContent())
.publishIf(configTable::hasAnyContent, false)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST)
.withSelect(
configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION),
PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent())
.publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent(), false)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG)
.withExec(SebExamConfigImportPopup.importFunction(this.pageService, true))
.noEventPropagation()
.publishIf(() -> examConfigGrant.im())
;
.publishIf(examConfigGrant::im);
}
}

View file

@ -9,14 +9,17 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.rap.rwt.RWT;
import org.eclipse.rap.rwt.client.service.UrlLauncher;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
@ -94,7 +97,9 @@ public class SebExamConfigPropForm implements TemplateComposer {
static final LocTextKey FORM_IMPORT_CONFIRM_TEXT_KEY =
new LocTextKey("sebserver.examconfig.action.import-config.confirm");
static final LocTextKey FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.attched-to");
new LocTextKey("sebserver.examconfig.form.attached-to");
static final LocTextKey FORM_ATTACHED_EXAMS_TITLE_TOOLTIP_TEXT_KEY =
new LocTextKey("sebserver.examconfig.form.attached-to" + Constants.TOOLTIP_TEXT_KEY_SUFFIX);
static final LocTextKey SAVE_CONFIRM_STATE_CHANGE_WHILE_ATTACHED =
new LocTextKey("sebserver.examconfig.action.state-change.confirm");
@ -186,7 +191,8 @@ public class SebExamConfigPropForm implements TemplateComposer {
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_NAME,
FORM_NAME_TEXT_KEY,
examConfig.name))
examConfig.name)
.mandatory(!isReadonly))
.addField(FormBuilder.text(
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_DESCRIPTION_TEXT_KEY,
@ -198,7 +204,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
FORM_STATUS_TEXT_KEY,
examConfig.status.name(),
() -> resourceService.examConfigStatusResources(isAttachedToExam))
.withEmptyCellSeparation((isReadonly) ? false : true))
.withEmptyCellSeparation(!isReadonly))
.buildFor((isNew)
? this.restService.getRestCall(NewExamConfig.class)
: this.restService.getRestCall(SaveExamConfig.class));
@ -214,15 +220,13 @@ public class SebExamConfigPropForm implements TemplateComposer {
.newAction(ActionDefinition.SEB_EXAM_CONFIG_PROP_MODIFY)
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW)
.withEntityKey(entityKey)
.publishIf(() -> isReadonly)
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY)
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && isReadonly && !settingsReadonly)
.withAttribute(PageContext.AttributeKeys.READ_ONLY, String.valueOf(!modifyGrant))
.publishIf(() -> modifyGrant && isReadonly)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_EXPORT_PLAIN_XML)
.withEntityKey(entityKey)
@ -288,11 +292,13 @@ public class SebExamConfigPropForm implements TemplateComposer {
if (isAttachedToExam && isReadonly) {
widgetFactory.labelSeparator(content);
widgetFactory.label(content, StringUtils.EMPTY);
widgetFactory.labelLocalized(
content,
CustomVariant.TEXT_H3,
FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY);
FORM_ATTACHED_EXAMS_TITLE_TEXT_KEY,
FORM_ATTACHED_EXAMS_TITLE_TOOLTIP_TEXT_KEY);
widgetFactory.labelSeparator(content);
final EntityTable<ExamConfigurationMap> table =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigMappingsPage.class))
@ -314,13 +320,17 @@ public class SebExamConfigPropForm implements TemplateComposer {
this.pageService.getI18nSupport().getUsersTimeZoneTitleSuffix()),
ExamConfigurationMap::getExamStartTime))
.withColumn(new ColumnDefinition<ExamConfigurationMap>(
.withColumn(new ColumnDefinition<>(
Domain.EXAM.ATTR_TYPE,
ExamList.COLUMN_TITLE_TYPE_KEY,
resourceService::localizedExamTypeName))
.withDefaultAction(this::showExamAction)
.withSelectionListener(this.pageService.getSelectionPublisher(
pageContext,
ActionDefinition.EXAM_VIEW_FROM_LIST))
.compose(pageContext.copyOf(content));
actionBuilder
@ -331,7 +341,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
return pageAction.withEntityKey(
new EntityKey(selectedExamMapping.examId, EntityType.EXAM));
})
.publishIf(table::hasAnyContent);
.publishIf(table::hasAnyContent, false);
}
}
@ -340,7 +350,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
.newAction(ActionDefinition.EXAM_VIEW_FROM_LIST)
.withSelectionSupplier(() -> {
final ExamConfigurationMap selectedROWData = getSelectedExamMapping(table);
return new HashSet<>(Arrays.asList(new EntityKey(selectedROWData.examId, EntityType.EXAM)));
return new HashSet<>(Collections.singletonList(new EntityKey(selectedROWData.examId, EntityType.EXAM)));
})
.withExec(PageAction::applySingleSelectionAsEntityKey)
.create();

View file

@ -202,7 +202,7 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
PageContext.AttributeKeys.CREATE_FROM_TEMPLATE,
Constants.FALSE_STRING)))
.noEventPropagation()
.publishIf(() -> examConfigGrant.iw())
.publishIf(examConfigGrant::iw)
.newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP)
.withEntityKey(entityKey)
@ -235,5 +235,4 @@ public class SebExamConfigSettingsForm implements TemplateComposer {
}
}
}
}

View file

@ -44,7 +44,8 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
* If the current user is the owner of the User-Account the password is required and must
* match the users current password.
* If the current user is an administrator that has to reset another users password the
* password that is also required must match the administrators current password. */
* password that is also required must match the administrators current password.
**/
public class UserAccountChangePasswordForm implements TemplateComposer {
private static final String FORM_TITLE_KEY = "sebserver.useraccount.form.pwchange.title";
@ -99,22 +100,25 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
.addField(FormBuilder.text(
PasswordChange.ATTR_NAME_PASSWORD,
FORM_PASSWORD_TEXT_KEY)
.asPasswordField())
.asPasswordField()
.mandatory())
.addField(FormBuilder.text(
PasswordChange.ATTR_NAME_NEW_PASSWORD,
FORM_PASSWORD_NEW_TEXT_KEY)
.asPasswordField())
.asPasswordField()
.mandatory())
.addFieldIf(
() -> entityKey != null,
() -> FormBuilder.text(
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
FORM_PASSWORD_NEW_CONFIRM_TEXT_KEY)
.asPasswordField())
.asPasswordField()
.mandatory())
.buildFor(this.restService.getRestCall(ChangePassword.class));
this.pageService.pageActionBuilder(pageContext)
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD_SAVE)
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSWORD_SAVE)
.withExec(action -> {
final PageAction saveAction = formHandle.processFormSave(action);
if (ownAccount) {

View file

@ -116,7 +116,7 @@ public class UserAccountForm implements TemplateComposer {
final UserAccount userAccount = isNew.getAsBoolean()
? UserMod.createNew((parentEntityKey != null)
? Long.valueOf(parentEntityKey.modelId)
: user.institutionId)
: currentUser.get().institutionId)
: restService
.getBuilder(GetUserAccount.class)
.withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId)
@ -136,7 +136,8 @@ public class UserAccountForm implements TemplateComposer {
PrivilegeType.WRITE,
EntityType.USER);
final boolean institutionActive = restService.getBuilder(GetInstitution.class)
final boolean institutionActive = userAccount.getInstitutionId() != null &&
restService.getBuilder(GetInstitution.class)
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(userAccount.getInstitutionId()))
.call()
.map(inst -> inst.active)
@ -170,8 +171,9 @@ public class UserAccountForm implements TemplateComposer {
Domain.USER.ATTR_INSTITUTION_ID,
FORM_INSTITUTION_TEXT_KEY,
String.valueOf(userAccount.getInstitutionId()),
() -> this.resourceService.institutionResource())
.readonlyIf(isNotNew))
this.resourceService::institutionResource)
.readonlyIf(isNotNew)
.mandatory(!readonly))
.addFieldIf(
() -> readonly,
() -> FormBuilder.text(
@ -182,15 +184,18 @@ public class UserAccountForm implements TemplateComposer {
.addField(FormBuilder.text(
Domain.USER.ATTR_NAME,
FORM_NAME_TEXT_KEY,
userAccount.getName()))
userAccount.getName())
.mandatory(!readonly))
.addField(FormBuilder.text(
Domain.USER.ATTR_SURNAME,
FORM_SURNAME_TEXT_KEY,
userAccount.getSurname()))
userAccount.getSurname())
.mandatory(!readonly))
.addField(FormBuilder.text(
Domain.USER.ATTR_USERNAME,
FORM_USERNAME_TEXT_KEY,
userAccount.getUsername()))
userAccount.getUsername())
.mandatory(!readonly))
.addField(FormBuilder.text(
Domain.USER.ATTR_EMAIL,
FORM_MAIL_TEXT_KEY,
@ -206,7 +211,8 @@ public class UserAccountForm implements TemplateComposer {
Domain.USER.ATTR_TIMEZONE,
FORM_TIMEZONE_TEXT_KEY,
userAccount.getTimeZone().getID(),
this.resourceService::timeZoneResources))
this.resourceService::timeZoneResources)
.mandatory(!readonly))
.addFieldIf(
() -> modifyGrant,
() -> FormBuilder.multiCheckboxSelection(
@ -214,19 +220,22 @@ public class UserAccountForm implements TemplateComposer {
FORM_ROLES_TEXT_KEY,
StringUtils.join(userAccount.getRoles(), Constants.LIST_SEPARATOR_CHAR),
this.resourceService::userRoleResources)
.visibleIf(writeGrant))
.visibleIf(writeGrant)
.mandatory(!readonly))
.addFieldIf(
isNew,
() -> FormBuilder.text(
PasswordChange.ATTR_NAME_NEW_PASSWORD,
FORM_PASSWORD_TEXT_KEY)
.asPasswordField())
.asPasswordField()
.mandatory(!readonly))
.addFieldIf(
isNew,
() -> FormBuilder.text(
PasswordChange.ATTR_NAME_CONFIRM_NEW_PASSWORD,
FORM_PASSWORD_CONFIRM_TEXT_KEY)
.asPasswordField())
.asPasswordField()
.mandatory(!readonly))
.buildFor((entityKey == null)
? restService.getRestCall(NewUserAccount.class)
: restService.getRestCall(SaveUserAccount.class));
@ -241,7 +250,7 @@ public class UserAccountForm implements TemplateComposer {
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && readonly && institutionActive)
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSOWRD)
.newAction(ActionDefinition.USER_ACCOUNT_CHANGE_PASSWORD)
.withEntityKey(entityKey)
.publishIf(() -> modifyGrant && readonly && institutionActive && userAccount.isActive())
@ -258,22 +267,25 @@ public class UserAccountForm implements TemplateComposer {
.newAction(ActionDefinition.USER_ACCOUNT_SAVE)
.withEntityKey(entityKey)
.withExec(action -> {
return formHandle.handleFormPost(formHandle.doAPIPost()
.withExec(action -> formHandle.handleFormPost(formHandle.doAPIPost()
.map(userInfo -> {
if (ownAccount) {
currentUser.refresh(userInfo);
}
return userInfo;
}),
action);
})
action))
.ignoreMoveAwayFromEdit()
.publishIf(() -> !readonly)
.newAction(ActionDefinition.USER_ACCOUNT_SAVE_AND_ACTIVATE)
.withEntityKey(entityKey)
.withExec(formHandle::saveAndActivate)
.ignoreMoveAwayFromEdit()
.publishIf(() -> !readonly && !ownAccount && !userAccount.isActive())
.newAction(ActionDefinition.USER_ACCOUNT_CANCEL_MODIFY)
.withExec(this.pageService.backToCurrentFunction())
.publishIf(() -> !readonly);
}
}

View file

@ -8,15 +8,6 @@
package ch.ethz.seb.sebserver.gui.content;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import org.apache.commons.lang3.BooleanUtils;
import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
@ -45,6 +36,14 @@ import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute;
import ch.ethz.seb.sebserver.gui.table.EntityTable;
import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType;
import ch.ethz.seb.sebserver.gui.widget.WidgetFactory;
import org.apache.commons.lang3.BooleanUtils;
import org.eclipse.swt.widgets.Composite;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
@Lazy
@Component
@ -190,6 +189,16 @@ public class UserAccountList implements TemplateComposer {
.withDefaultAction(actionBuilder
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
.create())
.withSelectionListener(this.pageService.getSelectionPublisher(
ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY,
ActionDefinition.USER_ACCOUNT_ACTIVATE,
ActionDefinition.USER_ACCOUNT_DEACTIVATE,
pageContext,
ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST,
ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST,
ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY))
.compose(pageContext.copyOf(content));
// propagate content actions to action-pane
@ -201,11 +210,16 @@ public class UserAccountList implements TemplateComposer {
.newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST)
.withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> table.hasAnyContent())
.publishIf(table::hasAnyContent, false)
.newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST)
.withSelect(table::getSelection, this::editAction, EMPTY_SELECTION_TEXT_KEY)
.publishIf(() -> userGrant.im() && table.hasAnyContent());
.publishIf(() -> userGrant.im() && table.hasAnyContent(), false)
.newAction(ActionDefinition.USER_ACCOUNT_TOGGLE_ACTIVITY)
.withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY))
.withConfirm(this.pageService.confirmDeactivation(table))
.publishIf(() -> userGrant.m() && table.hasAnyContent(), false);
}
private PageAction editAction(final PageAction pageAction) {

View file

@ -197,6 +197,9 @@ public class UserActivityLogs implements TemplateComposer {
.noEventPropagation()
.create())
.withSelectionListener(this.pageService.getSelectionPublisher(
pageContext,
ActionDefinition.LOGS_USER_ACTIVITY_SHOW_DETAILS))
.compose(pageContext.copyOf(content));
actionBuilder
@ -206,11 +209,11 @@ public class UserActivityLogs implements TemplateComposer {
action -> this.showDetails(action, table.getSingleSelectedROWData()),
EMPTY_SELECTION_TEXT)
.noEventPropagation()
.publishIf(table::hasAnyContent);
.publishIf(table::hasAnyContent, false);
}
private final String getLogTime(final UserActivityLog log) {
private String getLogTime(final UserActivityLog log) {
if (log == null || log.timestamp == null) {
return Constants.EMPTY_NOTE;
}

View file

@ -109,6 +109,11 @@ public enum ActionDefinition {
ImageIcon.SAVE,
PageStateDefinitionImpl.USER_ACCOUNT_VIEW,
ActionCategory.FORM),
USER_ACCOUNT_SAVE_AND_ACTIVATE(
new LocTextKey("sebserver.form.action.save.activate"),
ImageIcon.ACTIVE,
PageStateDefinitionImpl.USER_ACCOUNT_VIEW,
ActionCategory.FORM),
USER_ACCOUNT_ACTIVATE(
new LocTextKey("sebserver.useraccount.action.activate"),
ImageIcon.TOGGLE_OFF,
@ -119,12 +124,18 @@ public enum ActionDefinition {
ImageIcon.TOGGLE_ON,
PageStateDefinitionImpl.USER_ACCOUNT_VIEW,
ActionCategory.FORM),
USER_ACCOUNT_CHANGE_PASSOWRD(
USER_ACCOUNT_TOGGLE_ACTIVITY(
new LocTextKey("sebserver.overall.action.toggle-activity"),
ImageIcon.SWITCH,
PageStateDefinitionImpl.USER_ACCOUNT_LIST,
ActionCategory.USER_ACCOUNT_LIST),
USER_ACCOUNT_CHANGE_PASSWORD(
new LocTextKey("sebserver.useraccount.action.change.password"),
ImageIcon.SECURE,
PageStateDefinitionImpl.USER_ACCOUNT_PASSWORD_CHANGE,
ActionCategory.FORM),
USER_ACCOUNT_CHANGE_PASSOWRD_SAVE(
USER_ACCOUNT_CHANGE_PASSWORD_SAVE(
new LocTextKey("sebserver.useraccount.action.change.password.save"),
ImageIcon.SAVE,
PageStateDefinitionImpl.USER_ACCOUNT_VIEW,
@ -353,6 +364,11 @@ public enum ActionDefinition {
ImageIcon.SAVE,
PageStateDefinitionImpl.SEB_CLIENT_CONFIG_VIEW,
ActionCategory.FORM),
SEB_CLIENT_CONFIG_SAVE_AND_ACTIVATE(
new LocTextKey("sebserver.form.action.save.activate"),
ImageIcon.ACTIVE,
PageStateDefinitionImpl.SEB_CLIENT_CONFIG_VIEW,
ActionCategory.FORM),
SEB_CLIENT_CONFIG_ACTIVATE(
new LocTextKey("sebserver.clientconfig.action.activate"),
ImageIcon.TOGGLE_OFF,
@ -363,6 +379,11 @@ public enum ActionDefinition {
ImageIcon.TOGGLE_ON,
PageStateDefinitionImpl.SEB_CLIENT_CONFIG_VIEW,
ActionCategory.FORM),
SEB_CLIENT_CONFIG_TOGGLE_ACTIVITY(
new LocTextKey("sebserver.overall.action.toggle-activity"),
ImageIcon.SWITCH,
PageStateDefinitionImpl.SEB_CLIENT_CONFIG_LIST,
ActionCategory.SEB_CLIENT_CONFIG_LIST),
SEB_CLIENT_CONFIG_EXPORT(
new LocTextKey("sebserver.clientconfig.action.export"),
ImageIcon.EXPORT,
@ -407,11 +428,7 @@ public enum ActionDefinition {
ImageIcon.EDIT_SETTINGS,
PageStateDefinitionImpl.SEB_EXAM_CONFIG_EDIT,
ActionCategory.FORM),
SEB_EXAM_CONFIG_VIEW(
new LocTextKey("sebserver.examconfig.action.view"),
ImageIcon.EDIT_SETTINGS,
PageStateDefinitionImpl.SEB_EXAM_CONFIG_VIEW,
ActionCategory.FORM),
SEB_EXAM_CONFIG_PROP_CANCEL_MODIFY(
new LocTextKey("sebserver.overall.action.modify.cancel"),
ImageIcon.CANCEL,
@ -422,6 +439,7 @@ public enum ActionDefinition {
ImageIcon.SAVE,
PageStateDefinitionImpl.SEB_EXAM_CONFIG_PROP_VIEW,
ActionCategory.FORM),
SEB_EXAM_CONFIG_EXPORT_PLAIN_XML(
new LocTextKey("sebserver.examconfig.action.export.plainxml"),
ImageIcon.EXPORT,
@ -641,15 +659,15 @@ public enum ActionDefinition {
public final PageStateDefinition targetState;
public final ActionCategory category;
private ActionDefinition(final LocTextKey title, final PageStateDefinition targetState) {
ActionDefinition(final LocTextKey title, final PageStateDefinition targetState) {
this(title, null, targetState, ActionCategory.VARIA);
}
private ActionDefinition(final LocTextKey title, final ImageIcon icon, final PageStateDefinition targetState) {
ActionDefinition(final LocTextKey title, final ImageIcon icon, final PageStateDefinition targetState) {
this(title, icon, targetState, ActionCategory.VARIA);
}
private ActionDefinition(
ActionDefinition(
final LocTextKey title,
final ImageIcon icon,
final ActionCategory category) {
@ -657,7 +675,7 @@ public enum ActionDefinition {
this(title, icon, null, category);
}
private ActionDefinition(
ActionDefinition(
final LocTextKey title,
final ImageIcon icon,
final PageStateDefinition targetState,

View file

@ -75,11 +75,10 @@ public enum PageStateDefinitionImpl implements PageStateDefinition {
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
SEB_EXAM_CONFIG_TEMPLATE_EDIT(Type.FORM_EDIT, ConfigTemplateForm.class,
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
SEB_EXAM_CONFIG_TEMPLATE_ATTRIBUTE_EDIT(
Type.FORM_EDIT,
ConfigTemplateAttributeForm.class,
ActivityDefinition.SEB_EXAM_CONFIG),
ActivityDefinition.SEB_EXAM_CONFIG_TEMPLATE),
MONITORING_RUNNING_EXAM_LIST(Type.LIST_VIEW, MonitoringRunningExamList.class, ActivityDefinition.MONITORING_EXAMS),
MONITORING_RUNNING_EXAM(Type.FORM_VIEW, MonitoringRunningExam.class, ActivityDefinition.MONITORING_EXAMS),

View file

@ -20,6 +20,8 @@ import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import ch.ethz.seb.sebserver.gbl.util.Tuple3;
import ch.ethz.seb.sebserver.gbl.util.Utils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTimeZone;
import org.springframework.beans.factory.annotation.Value;
@ -80,6 +82,7 @@ public class ResourceService {
private static final String MISSING_CLIENT_PING_NAME_KEY = "MISSING";
public static final Comparator<Tuple<String>> RESOURCE_COMPARATOR = (t1, t2) -> t1._2.compareTo(t2._2);
public static final Comparator<Tuple3<String>> RESOURCE_COMPARATOR_TUPLE_3 = (t1, t2) -> t1._2.compareTo(t2._2);
public static final EnumSet<EntityType> ENTITY_TYPE_EXCLUDE_MAP = EnumSet.of(
EntityType.ADDITIONAL_ATTRIBUTES,
@ -101,7 +104,6 @@ public class ResourceService {
public static final String USERACCOUNT_ROLE_PREFIX = "sebserver.useraccount.role.";
public static final String EXAM_INDICATOR_TYPE_PREFIX = "sebserver.exam.indicator.type.";
public static final String LMSSETUP_TYPE_PREFIX = "sebserver.lmssetup.type.";
public static final String LMSSETUP_PROXY_AUTH_TYPE_PREFIX = "sebserver.lmssetup.form.proxy.auth-type.";
public static final String CONFIG_ATTRIBUTE_TYPE_PREFIX = "sebserver.configtemplate.attr.type.";
public static final String SEB_RESTRICTION_WHITE_LIST_PREFIX = "sebserver.exam.form.sebrestriction.whiteListPaths.";
public static final String SEB_RESTRICTION_PERMISSIONS_PREFIX = "sebserver.exam.form.sebrestriction.permissions.";
@ -200,10 +202,13 @@ public class ResourceService {
public List<Tuple<String>> indicatorTypeResources() {
return Arrays.asList(IndicatorType.values())
.stream()
.map(type -> new Tuple<>(
.map(type -> new Tuple3<>(
type.name(),
this.i18nSupport.getText(EXAM_INDICATOR_TYPE_PREFIX + type.name(), type.name())))
.sorted(RESOURCE_COMPARATOR)
this.i18nSupport.getText(EXAM_INDICATOR_TYPE_PREFIX + type.name(), type.name()),
Utils.formatLineBreaks(this.i18nSupport.getText(
EXAM_INDICATOR_TYPE_PREFIX + type.name() + Constants.TOOLTIP_TEXT_KEY_SUFFIX,
StringUtils.EMPTY))))
.sorted(RESOURCE_COMPARATOR_TUPLE_3)
.collect(Collectors.toList());
}
@ -219,9 +224,12 @@ public class ResourceService {
public List<Tuple<String>> userRoleResources() {
return UserRole.publicRolesForUser(this.currentUser.get())
.stream()
.map(ur -> new Tuple<>(
.map(ur -> new Tuple3<>(
ur.name(),
this.i18nSupport.getText(USERACCOUNT_ROLE_PREFIX + ur.name())))
this.i18nSupport.getText(USERACCOUNT_ROLE_PREFIX + ur.name()),
Utils.formatLineBreaks(this.i18nSupport.getText(
USERACCOUNT_ROLE_PREFIX + ur.name() + Constants.TOOLTIP_TEXT_KEY_SUFFIX,
StringUtils.EMPTY))))
.sorted(RESOURCE_COMPARATOR)
.collect(Collectors.toList());
}
@ -332,7 +340,6 @@ public class ResourceService {
/** Get a list of language key/name tuples for all supported languages in the
* language of the current users locale.
*
* @param i18nSupport I18nSupport to get the actual current users locale
* @return list of language key/name tuples for all supported languages in the language of the current users
* locale */
public List<Tuple<String>> languageResources() {
@ -359,9 +366,13 @@ public class ResourceService {
return Arrays.asList(ExamType.values())
.stream()
.filter(type -> type != ExamType.UNDEFINED)
.map(type -> new Tuple<>(
.map(type -> new Tuple3<>(
type.name(),
this.i18nSupport.getText(EXAM_TYPE_PREFIX + type.name())))
this.i18nSupport.getText(EXAM_TYPE_PREFIX + type.name()),
Utils.formatLineBreaks(this.i18nSupport.getText(
this.i18nSupport.getText(EXAM_TYPE_PREFIX + type.name()) + Constants.TOOLTIP_TEXT_KEY_SUFFIX,
StringUtils.EMPTY))
))
.sorted(RESOURCE_COMPARATOR)
.collect(Collectors.toList());
}
@ -380,9 +391,13 @@ public class ResourceService {
return status != ConfigurationStatus.IN_USE;
}
})
.map(type -> new Tuple<>(
.map(type -> new Tuple3<>(
type.name(),
this.i18nSupport.getText(EXAMCONFIG_STATUS_PREFIX + type.name())))
this.i18nSupport.getText(EXAMCONFIG_STATUS_PREFIX + type.name()),
Utils.formatLineBreaks(this.i18nSupport.getText(
this.i18nSupport.getText(EXAMCONFIG_STATUS_PREFIX + type.name()) + Constants.TOOLTIP_TEXT_KEY_SUFFIX,
StringUtils.EMPTY))
))
.sorted(RESOURCE_COMPARATOR)
.collect(Collectors.toList());
}

View file

@ -176,6 +176,11 @@ public interface I18nSupport {
* @return the text in current language parsed from localized text */
String getText(String key, Locale locale, String def, Object... args);
/** Indicates if there is a localized text defined for a specified LocTextKey
*
* @param locTextKey the LocTextKey instance
* @return true if there is a localized text defined for a specified LocTextKey, false otherwise
*/
boolean hasText(LocTextKey locTextKey);
}

View file

@ -116,7 +116,7 @@ public final class PolyglotPageServiceImpl implements PolyglotPageService {
if (locTextKey != null) {
b.setText(this.i18nSupport.getText(locTextKey));
}
if (locToolTipKey != null) {
if (i18nSupport.hasText(locToolTipKey)) {
b.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(locToolTipKey)));
}
};
@ -200,13 +200,11 @@ public final class PolyglotPageServiceImpl implements PolyglotPageService {
.equals(locale.getLanguage())));
languageSelection.setData(RWT.CUSTOM_VARIANT, "header");
languageSelection.setText("| " + locale.getLanguage().toUpperCase(locale));
languageSelection.addListener(SWT.MouseDown, event -> {
this.setPageLocale(composerCtx.getRoot(), locale);
});
languageSelection.addListener(SWT.MouseDown, event -> this.setPageLocale(composerCtx.getRoot(), locale));
}
}
private static final Consumer<Label> labelFunction(
private static Consumer<Label> labelFunction(
final LocTextKey locTextKey,
final LocTextKey locToolTipKey,
final I18nSupport i18nSupport) {
@ -215,13 +213,13 @@ public final class PolyglotPageServiceImpl implements PolyglotPageService {
if (locTextKey != null) {
label.setText(i18nSupport.getText(locTextKey));
}
if (locToolTipKey != null) {
if (i18nSupport.hasText(locToolTipKey)) {
label.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey)));
}
};
}
private static final Consumer<Group> groupFunction(
private static Consumer<Group> groupFunction(
final LocTextKey locTextKey,
final LocTextKey locToolTipKey,
final I18nSupport i18nSupport) {
@ -230,13 +228,13 @@ public final class PolyglotPageServiceImpl implements PolyglotPageService {
if (locTextKey != null) {
group.setText(i18nSupport.getText(locTextKey));
}
if (locToolTipKey != null) {
if (i18nSupport.hasText(locToolTipKey)) {
group.setToolTipText(Utils.formatLineBreaks(i18nSupport.getText(locToolTipKey, StringUtils.EMPTY)));
}
};
}
private static final void updateLocale(final TabItem[] items, final I18nSupport i18nSupport) {
private static void updateLocale(final TabItem[] items, final I18nSupport i18nSupport) {
if (items == null) {
return;
}
@ -249,7 +247,7 @@ public final class PolyglotPageServiceImpl implements PolyglotPageService {
}
}
private static final void updateLocale(final TreeItem[] items, final I18nSupport i18nSupport) {
private static void updateLocale(final TreeItem[] items, final I18nSupport i18nSupport) {
if (items == null) {
return;
}

View file

@ -14,6 +14,8 @@ import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import ch.ethz.seb.sebserver.gbl.util.Tuple3;
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
@ -69,6 +71,11 @@ public final class MultiSelectionCheckbox extends Composite implements Selection
}
});
this.checkboxes.put(tuple._1, button);
Tuple3<String> tuple3 = tuple.adaptTo(Tuple3.class);
if (tuple3 != null && StringUtils.isNotBlank(tuple3._3)) {
button.setToolTipText(tuple3._3);
}
}
if (StringUtils.isNotBlank(selectionValue)) {

View file

@ -59,6 +59,8 @@ sebserver.overall.types.entityType.INSTITUTION=Institution
sebserver.overall.types.entityType.SEB_CLIENT_CONFIGURATION=Client Configuration
sebserver.overall.types.entityType.LMS_SETUP=LMS Setup
sebserver.overall.types.entityType.USER=User Account
sebserver.overall.types.entityType.CLIENT_INSTRUCTION=SEB Client Instruction
sebserver.overall.types.entityType.EXAM_SEB_RESTRICTION=SEB Exam Restriction
sebserver.overall.activity.title.serveradmin=SEB Server Administration
sebserver.overall.activity.title.sebconfig=SEB Configuration
@ -174,18 +176,27 @@ sebserver.institution.form.logoImage.unsupportedFileType=The selected file is no
sebserver.useraccount.list.actions=
sebserver.useraccount.role.SEB_SERVER_ADMIN=SEB Server Administrator
sebserver.useraccount.role.SEB_SERVER_ADMIN.tooltip=A SEB server administrator has overall read privileges</br>and is able to create new institutions and user accounts
sebserver.useraccount.role.INSTITUTIONAL_ADMIN=Institutional Administrator
sebserver.useraccount.role.INSTITUTIONAL_ADMIN.tooltip=An institutional administrator has overall read privileges on the assigned institution</br>and is able to edit the institution and create new user accounts for the institution.</br>Furthermore an institutional administrator is able to create new LMS bindings and SEB client configurations for the institution.
sebserver.useraccount.role.EXAM_ADMIN=Exam Administrator
sebserver.useraccount.role.EXAM_ADMIN.tooltip=An exam administrator has overall read privileges for the institution but cannot see or manage other user accounts.</br>An exam administrator is able to create new SEB configurations and import and setup exams.
sebserver.useraccount.role.EXAM_SUPPORTER=Exam Supporter
sebserver.useraccount.role.EXAM_SUPPORTER.tooltip=An exam supporter can only see and edit the own user account</br> and monitor exams for that he/she was attached by an exam administrator.
sebserver.useraccount.list.empty=No user account has been found. Please adapt the filter or create a new user account
sebserver.useraccount.list.title=User Accounts
sebserver.useraccount.list.column.institution=Institution
sebserver.useraccount.list.column.institution.tooltip=The institution of the user account.</br></br>Use the filter above to specify the institution.</br>{0}
sebserver.useraccount.list.column.name=First Name
sebserver.useraccount.list.column.name.tooltip=The first name of the user.</br></br>Use the filter above to narrow down a specific first name.</br>{0}
sebserver.useraccount.list.column.username=User Name
sebserver.useraccount.list.column.username.tooltip=The internal user name of the user.</br></br>Use the filter above to narrow down a specific user name.</br>{0}
sebserver.useraccount.list.column.email=Mail
sebserver.useraccount.list.column.email.tooltip=The e-mail address of the user.</br></br>Use the filter above to narrow down a specific e-mail address.</br>{0}
sebserver.useraccount.list.column.language=Language
sebserver.useraccount.list.column.active=Active
sebserver.useraccount.list.column.active.tooltip=The activity of the user.</br></br>Use the filter above to specify the activity.</br>{0}
sebserver.useraccount.action.list=User Account
sebserver.useraccount.action.form=User Account of {0}
@ -206,19 +217,32 @@ sebserver.useraccount.info.notEditable=You have no edit rights for this User Acc
sebserver.useraccount.form.title=User Account
sebserver.useraccount.form.title.new=Add User Account
sebserver.useraccount.form.institution=Institution
sebserver.useraccount.form.institution.tooltip=The institution the user belongs to.
sebserver.useraccount.form.creationdate=Creation Date
sebserver.useraccount.form.creationdate.tooltip=The date when the user-account was first created.
sebserver.useraccount.form.name=First Name
sebserver.useraccount.form.name.tooltip=The first name of the user.
sebserver.useraccount.form.surname=Surname
sebserver.useraccount.form.surname.tooltip=The last- or surname of the user.
sebserver.useraccount.form.username=Username
sebserver.useraccount.form.username.tooltip=The internal user name of the account.
sebserver.useraccount.form.mail=E-Mail
sebserver.useraccount.form.mail.tooltip=The e-mail address of the user.
sebserver.useraccount.form.language=Language
sebserver.useraccount.form.language.tooltip=The users language.
sebserver.useraccount.form.timezone=Time Zone
sebserver.useraccount.form.timezone.tooltip=The time-zone of the user.</br></br>Note that this also defines the exact time and date that is displayed to the user.
sebserver.useraccount.form.roles=User Roles
sebserver.useraccount.form.roles.tooltip=Select the roles for the user.</br>A user can have more then one role but must have at least one.</br></br>Please use the tooltip on the role name for more information about a specific role.
sebserver.useraccount.form.password=Password
sebserver.useraccount.form.password.tooltip=The password of the user account
sebserver.useraccount.form.password.confirm=Confirm Password
sebserver.useraccount.form.password.confirm.tooltip=Please confirm the password
sebserver.useraccount.form.pwchange.title=Change Password : {0}
sebserver.useraccount.form.password.new=New Password
sebserver.useraccount.form.password.new.tooltip=The new password for the user account
sebserver.useraccount.form.password.new.confirm=Confirm New Password
sebserver.useraccount.form.password.new.confirm.tooltip=Please confirm the password
################################
# LMS Setup
@ -465,19 +489,28 @@ sebserver.clientconfig.list.empty=There is currently no SEB-Client configuration
sebserver.clientconfig.list.title=SEB Client Configurations
sebserver.clientconfig.list.actions=
sebserver.clientconfig.list.column.institution=Institution
sebserver.clientconfig.list.column.institution.tooltip=The institution of the SEB client configuration.</br></br>Use the filter above to specify the institution.</br>{0}
sebserver.clientconfig.list.column.name=Name
sebserver.clientconfig.list.column.name.tooltip=The name of the SEB client configuration.</br></br>Use the filter above to narrow down a specific name.</br>{0}
sebserver.clientconfig.list.column.date=Creation Date {0}
sebserver.clientconfig.list.column.date.tooltip=The date when the SEB client configuration was first created.</br></br>Use the filter above to specify a from-date.</br>{0}
sebserver.clientconfig.list.column.active=Active
sebserver.clientconfig.list.column.active.tooltip=The activity of SEB client configuration.</br></br>Use the filter above to specify the activity.</br>{0}
sebserver.clientconfig.info.pleaseSelect=Please select first a Client Configuration from the list
sebserver.clientconfig.list.action.no.modify.privilege=No Access: A SEB Client Configuration from other institution cannot be modified.
sebserver.clientconfig.form.title.new=Add Client Configuration
sebserver.clientconfig.form.title=SEB Client Configuration
sebserver.clientconfig.form.name=Name
sebserver.clientconfig.form.name.tooltip=The name of the SEB Client Configuration.</br>Can be any name that not already exists for another SEB Client Configuration
sebserver.clientconfig.form.fallback-url=Fallback Start URL
sebserver.clientconfig.form.fallback-url.tooltip=A fallback URL that tells the SEB where to go when the SEB Server service is unavailable.
sebserver.clientconfig.form.date=Creation Date
sebserver.clientconfig.form.date.tooltip=The date when the SEB client configuration was first created.
sebserver.clientconfig.form.encryptSecret=Configuration Password
sebserver.clientconfig.form.encryptSecret.tooltip=Define a password if the SEB client configuration shall be password-encrypted
sebserver.clientconfig.form.encryptSecret.confirm=Confirm Password
sebserver.clientconfig.form.encryptSecret.confirm.tooltip=Please retype the given password for configrmation
sebserver.clientconfig.action.list.new=Add Configuration
sebserver.clientconfig.action.list.view=View Configuration
@ -494,9 +527,13 @@ sebserver.clientconfig.action.deactivate=Deactivate Configuration
sebserver.examconfig.action.list=Exam Configuration
sebserver.examconfig.list.title=Exam Configurations
sebserver.examconfig.list.column.institution=Institution
sebserver.examconfig.list.column.institution.tooltip=The institution of the SEB exam configuration.</br></br>Use the filter above to specify the institution.</br>{0}
sebserver.examconfig.list.column.name=Name
sebserver.examconfig.list.column.name.tooltip=The name of the SEB exam configuration.</br></br>Use the filter above to narrow down a specific name.</br>{0}
sebserver.examconfig.list.column.description=Description
sebserver.examconfig.list.column.description.tooltip=The description of the SEB exam configuration.</br></br>Use the filter above to find configurations that contains specific words or phrases within the description.</br>{0}
sebserver.examconfig.list.column.status=Status
sebserver.examconfig.list.column.status.tooltip=The status of the SEB exam configuration.</br></br>Use the filter above to specify a status.</br>{0}
sebserver.examconfig.list.actions=
@ -506,10 +543,9 @@ sebserver.examconfig.list.action.no.modify.privilege=No Access: An Exam Configur
sebserver.examconfig.action.list.new=Add Exam Configuration
sebserver.examconfig.action.list.view=View Configuration
sebserver.examconfig.action.list.modify=Edit Settings
sebserver.examconfig.action.list.modify=Configuration Settings
sebserver.examconfig.action.list.modify.properties=Edit Configuration
sebserver.examconfig.action.view=View Settings
sebserver.examconfig.action.modify=Edit Settings
sebserver.examconfig.action.modify=Configuration Settings
sebserver.examconfig.action.modify.properties=Edit Configuration
sebserver.examconfig.action.view.properties=View Configuration
sebserver.examconfig.action.save=Save
@ -534,12 +570,17 @@ sebserver.examconfig.action.state-change.confirm=This configuration is already a
sebserver.examconfig.form.title.new=Add Exam Configuration
sebserver.examconfig.form.title=Exam Configuration
sebserver.examconfig.form.name=Name
sebserver.examconfig.form.name.tooltip=The name of the SEB exam configuration.
sebserver.examconfig.form.description=Description
sebserver.examconfig.form.description.tooltip=The description text of the SEB exam configuration.
sebserver.examconfig.form.with-history=With History
sebserver.examconfig.form.template=Template
sebserver.examconfig.form.template.tooltip=The template this SEB exam configuration depends on.
sebserver.examconfig.form.status=Status
sebserver.examconfig.form.status.tooltip=The status of this SEB exam configuration.</br></br>Under Construction marks a SEB exam configuration to not be able to attach to an exam so far.</br></br>Ready to use marks an SEB exam configuration to be able to attach to an exam.</br></br>In Use marks a SEB exam configuration is already been used from one or more exam(s)
sebserver.examconfig.form.config-key.title=Config Key
sebserver.examconfig.form.attched-to=Attached To Exam
sebserver.examconfig.form.attached-to=Attached To Exam
sebserver.examconfig.form.attached-to.tooltip=This SEB exam configuration is currently attached to the following exams.</br></br>Select an exam from the list and use the "View Exam" or Double-Click on the list to go to a specific exam.
sebserver.examconfig.status.CONSTRUCTION=Under Construction
sebserver.examconfig.status.READY_TO_USE=Ready To Use
@ -1037,7 +1078,9 @@ sebserver.configtemplate.action.create-config.dialog=Exam Configuration
sebserver.configtemplate.form.title.new=Add Template
sebserver.configtemplate.form.title=Configuration Template
sebserver.configtemplate.form.name=Name
sebserver.configtemplate.form.name.tooltip=The name of the SEB exam configuration template
sebserver.configtemplate.form.description=Description
sebserver.configtemplate.form.description.tooltip=The description of the SEB exam configuration template
sebserver.configtemplate.action.save=Save Template
sebserver.configtemplate.attr.type.TEXT_FIELD=Text Field
@ -1058,10 +1101,15 @@ sebserver.configtemplate.attr.type.INLINE_TABLE=Table
sebserver.configtemplate.attr.type.COMPOSITE_TABLE=Table
sebserver.configtemplate.attrs.list.title=Configuration Attributes
sebserver.configtemplate.attrs.list.title.tooltip=Table of all SEB exam configuration attributes of this template
sebserver.configtemplate.attrs.list.name=Name
sebserver.configtemplate.attrs.list.name.tooltip=The technical name of the SEB exam configuration attribute with the display name in brackets if available.</br></br>{0}
sebserver.configtemplate.attrs.list.view=View
sebserver.configtemplate.attrs.list.view.tooltip=The view/tab where the SEB exam configuration attribute belongs to.</br></br>{0}
sebserver.configtemplate.attrs.list.group=Group
sebserver.configtemplate.attrs.list.group.tooltip=The group on the view/tab where the SEB exam configuration attribute belongs to.</br></br>{0}
sebserver.configtemplate.attrs.list.type=Type
sebserver.configtemplate.attrs.list.type.tooltip=The type of the SEB exam configuration attribute.</br></br>{0}
sebserver.configtemplate.attr.list.actions=
sebserver.configtemplate.attr.list.actions.modify=Edit Attribute
@ -1072,10 +1120,15 @@ sebserver.configtemplate.attr.info.pleaseSelect=Please select first an Attribute
sebserver.configtemplate.attr.form.title=Template Attribute
sebserver.configtemplate.attr.form.name=Name
sebserver.configtemplate.attr.form.name.tooltip=The technical name of the SEB exam configuration attribute with the display name in brackets if available.
sebserver.configtemplate.attr.form.type=Type
sebserver.configtemplate.attr.form.type.tooltip=The type of the SEB exam configuration attribute.
sebserver.configtemplate.attr.form.view=View
sebserver.configtemplate.attr.form.view.tooltip=The view/tab where the SEB exam configuration attribute belongs to.
sebserver.configtemplate.attr.form.group=Group
sebserver.configtemplate.attr.form.group.tooltip=The group on the view/tab where the SEB exam configuration attribute belongs to.
sebserver.configtemplate.attr.form.value=Template Attribute Value
sebserver.configtemplate.attr.form.value.tooltip=The SEB exam configuration attribute value that can be set as default for this template
sebserver.configtemplate.attr.action.setdefault=Set Default Values
sebserver.configtemplate.attr.action.template=View Template
@ -1165,10 +1218,15 @@ sebserver.logs.activity.seblogs.details=Show Details
sebserver.userlogs.list.title=User Activity Logs
sebserver.userlogs.list.column.institution=Institution
sebserver.userlogs.list.column.institution.tooltip=The institution of the user activity log.</br></br>Use the filter above to specify the institution.</br>{0}
sebserver.userlogs.list.column.user=User
sebserver.userlogs.list.column.user.tooltip=The user account of the user activity log.</br></br>Use the filter above to specify a user account.</br>{0}
sebserver.userlogs.list.column.dateTime=Date {0}
sebserver.userlogs.list.column.dateTime.tooltip=The date when the user activity log happened.</br></br>Use the filter above to specify a from- and to-date range.</br>{0}
sebserver.userlogs.list.column.activityType=User Activity
sebserver.userlogs.list.column.entityType=Entity Type
sebserver.userlogs.list.column.activityType.tooltip=The type of the user activity.</br></br>Use the filter above to specify a activity type.</br>{0}
sebserver.userlogs.list.column.entityType=Domain Type
sebserver.userlogs.list.column.entityType.tooltip=The domain type of the user activity.</br></br>Use the filter above to specify a domain type.</br>{0}
sebserver.userlogs.list.column.entityId=Entity-ID
sebserver.userlogs.list.column.message=Message

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 1.7 KiB