SEBSERV-27 #Insitution List and actions
This commit is contained in:
parent
60bd32c2cb
commit
04d438923d
50 changed files with 1296 additions and 335 deletions
|
@ -56,6 +56,11 @@ public class EntityName implements ModelIdAware, ModelNameAware {
|
|||
return this.modelId;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public EntityKey getEntityKey() {
|
||||
return new EntityKey(getModelId(), getEntityType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
|
|
|
@ -95,7 +95,7 @@ public final class LmsSetupTestResult {
|
|||
}
|
||||
|
||||
public static final LmsSetupTestResult ofQuizRequestError(final String message) {
|
||||
return new LmsSetupTestResult(false, null, null, message);
|
||||
return new LmsSetupTestResult(false, Collections.emptyList(), null, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -88,6 +88,12 @@ public final class Result<T> {
|
|||
}
|
||||
}
|
||||
|
||||
public void handleError(final Consumer<Throwable> errorHandler) {
|
||||
if (this.error != null) {
|
||||
errorHandler.accept(this.error);
|
||||
}
|
||||
}
|
||||
|
||||
/** Use this to get the resulting value or (if null) to get a given other value
|
||||
*
|
||||
* @param other the other value to get if the computed value is null
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
|
||||
public final class RWTUtils {
|
||||
|
||||
public static final String TEXT_NAME_H2 = "h2";
|
||||
|
||||
public static void clearComposite(final Composite parent) {
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Control control : parent.getChildren()) {
|
||||
control.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,9 @@ package ch.ethz.seb.sebserver.gui.service.page;
|
|||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
|
||||
|
||||
public interface PageContext {
|
||||
|
@ -30,7 +33,10 @@ public interface PageContext {
|
|||
|
||||
public static final String ATTR_PAGE_TEMPLATE_COMPOSER_NAME = "ATTR_PAGE_TEMPLATE_COMPOSER_NAME";
|
||||
|
||||
public static final String INSTITUTION_ID = "INSTITUTION_ID";
|
||||
public static final String ATTR_ENTITY_ID = "ENTITY_ID";
|
||||
public static final String ATTR_PARENT_ENTITY_ID = "PARENT_ENTITY_ID";
|
||||
public static final String ATTR_ENTITY_TYPE = "ENTITY_TYPE";
|
||||
public static final String ATTR_PARENT_ENTITY_TYPE = "PARENT_ENTITY_TYPE";
|
||||
|
||||
// public static final String USER_NAME = "USER_NAME";
|
||||
// public static final String PASSWORD = "PASSWORD";
|
||||
|
@ -86,6 +92,8 @@ public interface PageContext {
|
|||
* @return this PageContext instance (builder pattern) */
|
||||
PageContext withAttr(String key, String value);
|
||||
|
||||
PageContext withSelection(ActivitySelection selection);
|
||||
|
||||
String getAttribute(String name);
|
||||
|
||||
String getAttribute(String name, String def);
|
||||
|
@ -99,6 +107,8 @@ public interface PageContext {
|
|||
* @param event the concrete PageEvent instance */
|
||||
<T extends PageEvent> void publishPageEvent(T event);
|
||||
|
||||
Action createAction(ActionDefinition actionDefinition);
|
||||
|
||||
/** Apply a confirm dialog with a specified confirm message and a callback code
|
||||
* block that will be executed on users OK selection.
|
||||
*
|
||||
|
@ -125,4 +135,6 @@ public interface PageContext {
|
|||
|
||||
<T> T logoutOnError(Throwable error);
|
||||
|
||||
void publishPageMessage(PageMessageException pme);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.page;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
|
||||
|
||||
public interface PageEventListener<T extends PageEvent> {
|
||||
|
||||
String LISTENER_ATTRIBUTE_KEY = "PageEventListener";
|
||||
|
||||
boolean match(Class<? extends PageEvent> eventType);
|
||||
|
||||
default int priority() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void notify(T event);
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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.page;
|
||||
|
||||
public class PageMessageException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -6967378384991469166L;
|
||||
|
||||
public PageMessageException(final String message, final Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public PageMessageException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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.page.action;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
|
||||
public class Action implements Runnable {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(Action.class);
|
||||
|
||||
public final ActionDefinition definition;
|
||||
String confirmationMessage;
|
||||
String successMessage;
|
||||
boolean updateOnSelection;
|
||||
|
||||
final RestService restService;
|
||||
final PageContext pageContext;
|
||||
Function<Action, Result<?>> exec;
|
||||
Supplier<Set<String>> selectionSupplier;
|
||||
|
||||
public Action(
|
||||
final ActionDefinition definition,
|
||||
final PageContext pageContext,
|
||||
final RestService restService) {
|
||||
|
||||
this.definition = definition;
|
||||
this.pageContext = pageContext;
|
||||
this.restService = restService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (StringUtils.isNotBlank(this.confirmationMessage)) {
|
||||
this.pageContext.applyConfirmDialog(
|
||||
this.confirmationMessage,
|
||||
() -> exec());
|
||||
} else {
|
||||
exec();
|
||||
}
|
||||
}
|
||||
|
||||
private void exec() {
|
||||
try {
|
||||
|
||||
this.exec.apply(this)
|
||||
.map(value -> {
|
||||
this.pageContext.publishPageEvent(
|
||||
new ActionEvent(this.definition, value));
|
||||
return value;
|
||||
})
|
||||
.getOrThrow();
|
||||
|
||||
} catch (final PageMessageException pme) {
|
||||
Action.this.pageContext.publishPageMessage(pme);
|
||||
} catch (final Throwable t) {
|
||||
log.error("Failed to execute action: {}", Action.this, t);
|
||||
Action.this.pageContext.notifyError("action.error.unexpected.message", t);
|
||||
}
|
||||
}
|
||||
|
||||
public Action withExec(final Function<Action, Result<?>> exec) {
|
||||
this.exec = exec;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action withSelectionSupplier(final Supplier<Set<String>> selectionSupplier) {
|
||||
this.selectionSupplier = selectionSupplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action withConfirm(final String confirmationMessage) {
|
||||
this.confirmationMessage = confirmationMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action withSuccess(final String successMessage) {
|
||||
this.successMessage = successMessage;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Action withUpdateOnSelection() {
|
||||
this.updateOnSelection = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PageContext publish() {
|
||||
this.pageContext.publishPageEvent(new ActionPublishEvent(this));
|
||||
return this.pageContext;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,10 +13,14 @@ import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.IconButtonType;
|
|||
public enum ActionDefinition {
|
||||
|
||||
INSTITUTION_NEW(
|
||||
"actions.new.institution",
|
||||
"sebserver.institution.action.new",
|
||||
IconButtonType.NEW_ACTION),
|
||||
|
||||
INSTITUTION_MODIFY(
|
||||
"sebserver.institution.action.modify",
|
||||
IconButtonType.MODIFY_ACTION),
|
||||
|
||||
INSTITUTION_SAVE(
|
||||
"actions.modify.institution",
|
||||
IconButtonType.SAVE_ACTION),
|
||||
|
||||
|
|
|
@ -22,11 +22,12 @@ import org.springframework.stereotype.Component;
|
|||
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
|
@ -42,18 +43,21 @@ public class ActionPane implements TemplateComposer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void compose(final PageContext composerCtx) {
|
||||
public void compose(final PageContext pageContext) {
|
||||
|
||||
final Label label = this.widgetFactory.labelLocalized(
|
||||
composerCtx.getParent(),
|
||||
"h3",
|
||||
pageContext.getParent(),
|
||||
CustomVariant.TEXT_H2,
|
||||
new LocTextKey("sebserver.actionpane.title"));
|
||||
|
||||
final GridData titleLayout = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
titleLayout.verticalIndent = 10;
|
||||
titleLayout.horizontalIndent = 10;
|
||||
label.setLayoutData(titleLayout);
|
||||
|
||||
final Tree actions = this.widgetFactory.treeLocalized(composerCtx.getParent(), SWT.SINGLE | SWT.FULL_SELECTION);
|
||||
final Tree actions = this.widgetFactory.treeLocalized(
|
||||
pageContext.getParent(),
|
||||
SWT.SINGLE | SWT.FULL_SELECTION);
|
||||
actions.setData(RWT.CUSTOM_VARIANT, "actions");
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, true);
|
||||
actions.setLayoutData(gridData);
|
||||
|
@ -69,7 +73,7 @@ public class ActionPane implements TemplateComposer {
|
|||
actions.addListener(SWT.Selection, event -> {
|
||||
final TreeItem treeItem = (TreeItem) event.item;
|
||||
|
||||
final Runnable action = (Runnable) treeItem.getData(ACTION_EVENT_CALL_KEY);
|
||||
final Action action = (Action) treeItem.getData(ACTION_EVENT_CALL_KEY);
|
||||
action.run();
|
||||
|
||||
if (!treeItem.isDisposed()) {
|
||||
|
@ -82,12 +86,16 @@ public class ActionPane implements TemplateComposer {
|
|||
new ActionPublishEventListener() {
|
||||
@Override
|
||||
public void notify(final ActionPublishEvent event) {
|
||||
|
||||
final TreeItem actionItem = ActionPane.this.widgetFactory.treeItemLocalized(
|
||||
actions,
|
||||
event.actionDefinition.name);
|
||||
actionItem.setImage(event.actionDefinition.icon.getImage(composerCtx.getParent().getDisplay()));
|
||||
actionItem.setData(ACTION_EVENT_CALL_KEY,
|
||||
new SafeActionExecution(composerCtx, event, event.run));
|
||||
event.action.definition.name);
|
||||
|
||||
actionItem.setImage(event.action.definition.icon.getImage(
|
||||
pageContext.getParent().getDisplay()));
|
||||
|
||||
actionItem.setData(ACTION_EVENT_CALL_KEY, event.action);
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -8,9 +8,47 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.action;
|
||||
|
||||
public interface InstitutionActions {
|
||||
import static ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection.Activity.INSTITUTION_NODE;
|
||||
|
||||
// /** Use this higher-order function to create a new Institution action Runnable.
|
||||
import java.util.Collection;
|
||||
import java.util.function.Function;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityType;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.NewInstitution;
|
||||
import ch.ethz.seb.sebserver.gui.service.table.EntityTable;
|
||||
|
||||
public final class InstitutionActions {
|
||||
|
||||
public static Result<?> newInstitution(final Action action) {
|
||||
return action.restService
|
||||
.getBuilder(NewInstitution.class)
|
||||
.call();
|
||||
}
|
||||
|
||||
public static Function<Action, Result<?>> editInstitution(final EntityTable<?> fromTable) {
|
||||
return action -> {
|
||||
final Collection<String> selection = fromTable.getSelection();
|
||||
if (selection.isEmpty()) {
|
||||
return Result.ofError(new PageMessageException("sebserver.institution.info.pleaseSelect"));
|
||||
}
|
||||
|
||||
final EntityKey entityKey = new EntityKey(
|
||||
selection.iterator().next(),
|
||||
EntityType.INSTITUTION);
|
||||
action.pageContext.publishPageEvent(new ActivitySelectionEvent(
|
||||
INSTITUTION_NODE
|
||||
.createSelection()
|
||||
.withEntity(entityKey)));
|
||||
|
||||
return Result.of(entityKey);
|
||||
};
|
||||
}
|
||||
|
||||
// /** Use this higher-order function to create a new Institution action function.
|
||||
// *
|
||||
// * @return */
|
||||
// static Runnable newInstitution(final PageContext composerCtx, final RestServices restServices) {
|
||||
|
@ -23,7 +61,7 @@ public interface InstitutionActions {
|
|||
// };
|
||||
// }
|
||||
//
|
||||
// /** Use this higher-order function to create a delete Institution action Runnable.
|
||||
// /** Use this higher-order function to create a delete Institution action function.
|
||||
// *
|
||||
// * @return */
|
||||
// static Runnable deleteInstitution(final PageContext composerCtx, final RestServices restServices,
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.page.action;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionPublishEvent;
|
||||
|
||||
public class SafeActionExecution implements Runnable {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SafeActionExecution.class);
|
||||
|
||||
private final PageContext pageContext;
|
||||
private final ActionPublishEvent actionEvent;
|
||||
private final Runnable actionExecution;
|
||||
|
||||
public SafeActionExecution(
|
||||
final PageContext pageContext,
|
||||
final ActionPublishEvent actionEvent,
|
||||
final Runnable actionExecution) {
|
||||
|
||||
this.pageContext = pageContext;
|
||||
this.actionEvent = actionEvent;
|
||||
this.actionExecution = actionExecution;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if (StringUtils.isNotBlank(this.actionEvent.confirmationMessage)) {
|
||||
this.pageContext.applyConfirmDialog(
|
||||
this.actionEvent.confirmationMessage,
|
||||
createConfirmationCallback());
|
||||
} else {
|
||||
this.actionExecution.run();
|
||||
}
|
||||
} catch (final Throwable t) {
|
||||
log.error("Failed to execute action: {}", this.actionEvent, t);
|
||||
this.pageContext.notifyError("action.error.unexpected.message", t);
|
||||
}
|
||||
}
|
||||
|
||||
private final Runnable createConfirmationCallback() {
|
||||
return new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
SafeActionExecution.this.actionExecution.run();
|
||||
} catch (final Throwable t) {
|
||||
log.error("Failed to execute action: {}", SafeActionExecution.this.actionEvent, t);
|
||||
SafeActionExecution.this.pageContext.notifyError("action.error.unexpected.message", t);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -9,9 +9,7 @@
|
|||
package ch.ethz.seb.sebserver.gui.service.page.activity;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
|
@ -28,18 +26,18 @@ import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
|||
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection.Activity;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.impl.MainPageState;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutionNames;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
|
@ -76,7 +74,7 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
|
||||
final Label activities = this.widgetFactory.labelLocalized(
|
||||
pageContext.getParent(),
|
||||
"h3",
|
||||
CustomVariant.TEXT_H2,
|
||||
new LocTextKey("sebserver.activitiespane.title"));
|
||||
final GridData activitiesGridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
activitiesGridData.horizontalIndent = 20;
|
||||
|
@ -88,10 +86,10 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
navigationGridData.horizontalIndent = 10;
|
||||
navigation.setLayoutData(navigationGridData);
|
||||
|
||||
final List<EntityName> insitutionNames = this.restService
|
||||
.getBuilder(GetInstitutionNames.class)
|
||||
.call()
|
||||
.get(pageContext::notifyError, () -> Collections.emptyList());
|
||||
// final List<EntityName> insitutionNames = this.restService
|
||||
// .getBuilder(GetInstitutionNames.class)
|
||||
// .call()
|
||||
// .get(pageContext::notifyError, () -> Collections.emptyList());
|
||||
|
||||
if (userInfo.hasRole(UserRole.SEB_SERVER_ADMIN)) {
|
||||
// institutions (list) as root
|
||||
|
@ -100,12 +98,17 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
Activity.INSTITUTION_ROOT.title);
|
||||
ActivitySelection.inject(institutions, Activity.INSTITUTION_ROOT.createSelection());
|
||||
|
||||
for (final EntityName inst : insitutionNames) {
|
||||
createInstitutionItem(institutions, inst);
|
||||
}
|
||||
// for (final EntityName inst : insitutionNames) {
|
||||
// createInstitutionItem(institutions, inst);
|
||||
// }
|
||||
} else {
|
||||
final EntityName inst = insitutionNames.iterator().next();
|
||||
createInstitutionItem(navigation, inst);
|
||||
// institution node as none root
|
||||
final TreeItem institutions = this.widgetFactory.treeItemLocalized(
|
||||
navigation,
|
||||
Activity.INSTITUTION_ROOT.title);
|
||||
ActivitySelection.inject(institutions, Activity.INSTITUTION_NODE.createSelection());
|
||||
// final EntityName inst = insitutionNames.iterator().next();
|
||||
// createInstitutionItem(navigation, inst);
|
||||
}
|
||||
|
||||
// final TreeItem user = this.widgetFactory.treeItemLocalized(
|
||||
|
@ -222,21 +225,25 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
}
|
||||
}
|
||||
|
||||
static TreeItem createInstitutionItem(final Tree parent, final EntityName idAndName) {
|
||||
static TreeItem createInstitutionItem(final Tree parent, final EntityName entityName) {
|
||||
final TreeItem institution = new TreeItem(parent, SWT.NONE);
|
||||
createInstitutionItem(idAndName, institution);
|
||||
createInstitutionItem(entityName, institution);
|
||||
return institution;
|
||||
}
|
||||
|
||||
static TreeItem createInstitutionItem(final TreeItem parent, final EntityName idAndName) {
|
||||
static TreeItem createInstitutionItem(final TreeItem parent, final EntityName entityName) {
|
||||
final TreeItem institution = new TreeItem(parent, SWT.NONE);
|
||||
createInstitutionItem(idAndName, institution);
|
||||
createInstitutionItem(entityName, institution);
|
||||
return institution;
|
||||
}
|
||||
|
||||
static void createInstitutionItem(final EntityName idAndName, final TreeItem institution) {
|
||||
institution.setText(idAndName.name);
|
||||
ActivitySelection.inject(institution, Activity.INSTITUTION_NODE.createSelection(idAndName));
|
||||
static void createInstitutionItem(final EntityName entityName, final TreeItem institution) {
|
||||
institution.setText(entityName.name);
|
||||
ActivitySelection.inject(
|
||||
institution,
|
||||
Activity.INSTITUTION_NODE
|
||||
.createSelection()
|
||||
.withEntity(entityName.getEntityKey()));
|
||||
}
|
||||
|
||||
static final TreeItem findItemByActivity(
|
||||
|
@ -250,7 +257,7 @@ public class ActivitiesPane implements TemplateComposer {
|
|||
|
||||
for (final TreeItem item : items) {
|
||||
final ActivitySelection activitySelection = ActivitySelection.get(item);
|
||||
final String id = activitySelection.getObjectIdentifier();
|
||||
final String id = activitySelection.getEntityId();
|
||||
if (activitySelection != null && activitySelection.activity == activity &&
|
||||
(id == null || (objectId != null && objectId.equals(id)))) {
|
||||
return item;
|
||||
|
|
|
@ -8,11 +8,14 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.activity;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.swt.widgets.TreeItem;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityName;
|
||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
|
@ -30,7 +33,7 @@ public class ActivitySelection {
|
|||
};
|
||||
|
||||
public enum Activity {
|
||||
NONE(TODOTemplate.class, TODOTemplate.class, (String) null),
|
||||
NONE(TODOTemplate.class, TODOTemplate.class),
|
||||
INSTITUTION_ROOT(
|
||||
InstitutionList.class,
|
||||
ActionPane.class,
|
||||
|
@ -38,7 +41,7 @@ public class ActivitySelection {
|
|||
INSTITUTION_NODE(
|
||||
TODOTemplate.class,
|
||||
ActionPane.class,
|
||||
AttributeKeys.INSTITUTION_ID),
|
||||
new LocTextKey("sebserver.activities.inst")),
|
||||
//
|
||||
// USERS(UserAccountsForm.class, ActionPane.class),
|
||||
//
|
||||
|
@ -55,7 +58,7 @@ public class ActivitySelection {
|
|||
public final LocTextKey title;
|
||||
public final Class<? extends TemplateComposer> contentPaneComposer;
|
||||
public final Class<? extends TemplateComposer> actionPaneComposer;
|
||||
public final String objectIdentifierAttribute;
|
||||
//public final String modelIdAttribute;
|
||||
|
||||
private Activity(
|
||||
final Class<? extends TemplateComposer> objectPaneComposer,
|
||||
|
@ -65,43 +68,54 @@ public class ActivitySelection {
|
|||
this.title = title;
|
||||
this.contentPaneComposer = objectPaneComposer;
|
||||
this.actionPaneComposer = selectionPaneComposer;
|
||||
this.objectIdentifierAttribute = null;
|
||||
}
|
||||
|
||||
private Activity(
|
||||
final Class<? extends TemplateComposer> objectPaneComposer,
|
||||
final Class<? extends TemplateComposer> selectionPaneComposer,
|
||||
final String objectIdentifierAttribute) {
|
||||
final Class<? extends TemplateComposer> selectionPaneComposer) {
|
||||
|
||||
this.title = null;
|
||||
this.contentPaneComposer = objectPaneComposer;
|
||||
this.actionPaneComposer = selectionPaneComposer;
|
||||
this.objectIdentifierAttribute = objectIdentifierAttribute;
|
||||
}
|
||||
|
||||
public final ActivitySelection createSelection() {
|
||||
return new ActivitySelection(this);
|
||||
}
|
||||
|
||||
public final ActivitySelection createSelection(final EntityName entityName) {
|
||||
return new ActivitySelection(this, entityName);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String ATTR_ACTIVITY_SELECTION = "ACTIVITY_SELECTION";
|
||||
|
||||
public final Activity activity;
|
||||
public final EntityName entityName;
|
||||
final Map<String, String> attributes;
|
||||
Consumer<TreeItem> expandFunction = EMPTY_FUNCTION;
|
||||
|
||||
ActivitySelection(final Activity activity) {
|
||||
this(activity, null);
|
||||
this.activity = activity;
|
||||
this.attributes = new HashMap<>();
|
||||
}
|
||||
|
||||
ActivitySelection(final Activity activity, final EntityName entityName) {
|
||||
this.activity = activity;
|
||||
this.entityName = entityName;
|
||||
this.expandFunction = EMPTY_FUNCTION;
|
||||
public ActivitySelection withEntity(final EntityKey entityKey) {
|
||||
if (entityKey != null) {
|
||||
this.attributes.put(AttributeKeys.ATTR_ENTITY_ID, entityKey.modelId);
|
||||
this.attributes.put(AttributeKeys.ATTR_ENTITY_TYPE, entityKey.entityType.name());
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
}
|
||||
|
||||
public ActivitySelection withParentEntity(final EntityKey parentEntityKey) {
|
||||
if (parentEntityKey != null) {
|
||||
this.attributes.put(AttributeKeys.ATTR_PARENT_ENTITY_ID, parentEntityKey.modelId);
|
||||
this.attributes.put(AttributeKeys.ATTR_PARENT_ENTITY_TYPE, parentEntityKey.entityType.name());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, String> getAttributes() {
|
||||
return Collections.unmodifiableMap(this.attributes);
|
||||
}
|
||||
|
||||
public ActivitySelection withExpandFunction(final Consumer<TreeItem> expandFunction) {
|
||||
|
@ -112,44 +126,12 @@ public class ActivitySelection {
|
|||
return this;
|
||||
}
|
||||
|
||||
public String getObjectIdentifier() {
|
||||
if (this.entityName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.entityName.modelId;
|
||||
}
|
||||
|
||||
public void processExpand(final TreeItem item) {
|
||||
this.expandFunction.accept(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((this.activity == null) ? 0 : this.activity.hashCode());
|
||||
result = prime * result + ((this.entityName == null) ? 0 : this.entityName.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final ActivitySelection other = (ActivitySelection) obj;
|
||||
if (this.activity != other.activity)
|
||||
return false;
|
||||
if (this.entityName == null) {
|
||||
if (other.entityName != null)
|
||||
return false;
|
||||
} else if (!this.entityName.equals(other.entityName))
|
||||
return false;
|
||||
return true;
|
||||
public String getEntityId() {
|
||||
return this.attributes.get(AttributeKeys.ATTR_ENTITY_ID);
|
||||
}
|
||||
|
||||
public static ActivitySelection get(final TreeItem item) {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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.page.content;
|
||||
|
||||
public class Institution {
|
||||
|
||||
}
|
|
@ -16,13 +16,17 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.InstitutionActions;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetInstitutions;
|
||||
import ch.ethz.seb.sebserver.gui.service.table.ColumnDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.table.EntityTable;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
|
@ -49,37 +53,39 @@ public class InstitutionList implements TemplateComposer {
|
|||
content.setLayout(contentLayout);
|
||||
content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
|
||||
// title
|
||||
this.widgetFactory.labelLocalizedTitle(
|
||||
content,
|
||||
new LocTextKey("sebserver.institution.list.title"));
|
||||
|
||||
this.widgetFactory.entityTableBuilder(this.restService.getRestCall(GetInstitutions.class))
|
||||
.withPaging(3)
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_NAME,
|
||||
new LocTextKey("sebserver.institution.list.column.name"),
|
||||
null,
|
||||
0,
|
||||
entity -> entity.name,
|
||||
null,
|
||||
true))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_URL_SUFFIX,
|
||||
new LocTextKey("sebserver.institution.list.column.urlSuffix"),
|
||||
null,
|
||||
0,
|
||||
entity -> entity.urlSuffix,
|
||||
null,
|
||||
true))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_ACTIVE,
|
||||
new LocTextKey("sebserver.institution.list.column.active"),
|
||||
null,
|
||||
0,
|
||||
entity -> entity.active,
|
||||
null,
|
||||
true))
|
||||
.compose(content);
|
||||
// table
|
||||
final EntityTable<Institution> table =
|
||||
this.widgetFactory.entityTableBuilder(this.restService.getRestCall(GetInstitutions.class))
|
||||
.withPaging(3)
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_NAME,
|
||||
new LocTextKey("sebserver.institution.list.column.name"),
|
||||
entity -> entity.name,
|
||||
true))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_URL_SUFFIX,
|
||||
new LocTextKey("sebserver.institution.list.column.urlSuffix"),
|
||||
entity -> entity.urlSuffix,
|
||||
true))
|
||||
.withColumn(new ColumnDefinition<>(
|
||||
Domain.INSTITUTION.ATTR_ACTIVE,
|
||||
new LocTextKey("sebserver.institution.list.column.active"),
|
||||
entity -> entity.active,
|
||||
true))
|
||||
.compose(content);
|
||||
|
||||
// propagate content actions to action-pane
|
||||
pageContext.createAction(ActionDefinition.INSTITUTION_NEW)
|
||||
.withExec(InstitutionActions::newInstitution)
|
||||
.publish()
|
||||
.createAction(ActionDefinition.INSTITUTION_MODIFY)
|
||||
.withExec(InstitutionActions.editInstitution(table))
|
||||
.publish();
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ package ch.ethz.seb.sebserver.gui.service.page.event;
|
|||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
|
||||
|
||||
/** This Event is used to propagate a user-action to the GUI system.
|
||||
* Potentially every component can listen to an Event and react on the user-action */
|
||||
public final class ActionEvent implements PageEvent {
|
||||
|
||||
public final ActionDefinition actionDefinition;
|
||||
|
|
|
@ -13,7 +13,6 @@ import java.util.function.Predicate;
|
|||
|
||||
import org.eclipse.swt.widgets.Widget;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
|
||||
|
||||
public interface ActionEventListener extends PageEventListener<ActionEvent> {
|
||||
|
|
|
@ -8,46 +8,16 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
|
||||
/** This action is used to publish an Action to the Action-Pane for a specified context.
|
||||
* The ActionPane is listening to this events and render specified actions on notify */
|
||||
public class ActionPublishEvent implements PageEvent {
|
||||
|
||||
public final ActionDefinition actionDefinition;
|
||||
public final Runnable run;
|
||||
public final String confirmationMessage;
|
||||
public final String successMessage;
|
||||
public final Action action;
|
||||
|
||||
public ActionPublishEvent(
|
||||
final ActionDefinition actionDefinition,
|
||||
final Runnable run) {
|
||||
|
||||
this(actionDefinition, run, null, null);
|
||||
}
|
||||
|
||||
public ActionPublishEvent(
|
||||
final ActionDefinition actionDefinition,
|
||||
final Runnable run,
|
||||
final String confirmationMessage) {
|
||||
|
||||
this(actionDefinition, run, confirmationMessage, null);
|
||||
}
|
||||
|
||||
public ActionPublishEvent(
|
||||
final ActionDefinition actionDefinition,
|
||||
final Runnable run,
|
||||
final String confirmationMessage,
|
||||
final String successMessage) {
|
||||
|
||||
this.actionDefinition = actionDefinition;
|
||||
this.run = run;
|
||||
this.confirmationMessage = confirmationMessage;
|
||||
this.successMessage = successMessage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ActionPublishEvent [actionDefinition=" + this.actionDefinition + ", confirmationMessage="
|
||||
+ this.confirmationMessage + ", successMessage=" + this.successMessage + "]";
|
||||
public ActionPublishEvent(final Action action) {
|
||||
this.action = action;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageEventListener;
|
||||
|
||||
public interface ActionPublishEventListener extends PageEventListener<ActionPublishEvent> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageEventListener;
|
||||
|
||||
public interface ActivitySelectionListener extends PageEventListener<ActivitySelectionEvent> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageEventListener;
|
||||
|
||||
public interface LogoutEventListener extends PageEventListener<LogoutEvent> {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.page.event;
|
||||
|
||||
/** This is just a marker interface for all page events.
|
||||
* Page events can be published to the actual page tree by using PageContext.publishPageEvent
|
||||
*
|
||||
* Potentially every component on the actual page tree can listen to an certain page event
|
||||
* by adding a specified listener within the components setData functionality.
|
||||
* see PageListener for more information */
|
||||
public interface PageEvent {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.page.event;
|
||||
|
||||
/** Defines a listener for PageEvent.
|
||||
*
|
||||
* Potentially every component on the actual page tree can listen to an certain page event
|
||||
* by adding a specified listener within the components setData functionality.
|
||||
*
|
||||
* @param <T> the type of the PageEvent to listen to */
|
||||
public interface PageEventListener<T extends PageEvent> {
|
||||
|
||||
/** The key name used to register PageEventListener instances within the
|
||||
* setData functionality of a component */
|
||||
String LISTENER_ATTRIBUTE_KEY = "PageEventListener";
|
||||
|
||||
/** Used to check a concrete listener is interested in a specified type of PageEvent.
|
||||
*
|
||||
* @param eventType the PageEvent type
|
||||
* @return whether the listener is interested in being notified by the event or not */
|
||||
boolean match(Class<? extends PageEvent> eventType);
|
||||
|
||||
/** The listeners priority.
|
||||
* Use this if a dedicated order or sequence of listener notification is needed.
|
||||
* Default priority is 1
|
||||
*
|
||||
* @return the priority of the listener that defines in witch sequence listeners of the same
|
||||
* type get notified on a PageEvent propagation process on the current page-tree */
|
||||
default int priority() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void notify(T event);
|
||||
|
||||
}
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.page.form;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.eclipse.rap.rwt.RWT;
|
||||
import org.eclipse.swt.widgets.Combo;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Text;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FormBinding;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.SingleSelection;
|
||||
|
||||
public final class Form implements FormBinding {
|
||||
|
||||
private final JSONMapper jsonMapper;
|
||||
private final ObjectNode objectRoot;
|
||||
|
||||
private final Map<String, FormFieldAccessor<?>> formFields = new LinkedHashMap<>();
|
||||
private final Map<String, Form> subForms = new LinkedHashMap<>();
|
||||
private final Map<String, List<Form>> subLists = new LinkedHashMap<>();
|
||||
private final Map<String, Set<String>> groups = new LinkedHashMap<>();
|
||||
|
||||
Form(final JSONMapper jsonMapper) {
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.objectRoot = this.jsonMapper.createObjectNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFormAsJson() {
|
||||
try {
|
||||
flush();
|
||||
return this.jsonMapper.writeValueAsString(this.objectRoot);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException("Unexpected error while trying to create json form Form post: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getValue(final String name) {
|
||||
final FormFieldAccessor<?> formFieldAccessor = this.formFields.get(name);
|
||||
if (formFieldAccessor != null) {
|
||||
return formFieldAccessor.getValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void putStatic(final String name, final String value) {
|
||||
this.objectRoot.put(name, value);
|
||||
}
|
||||
|
||||
public void addToGroup(final String groupName, final String fieldName) {
|
||||
if (this.formFields.containsKey(fieldName)) {
|
||||
this.groups.computeIfAbsent(groupName, k -> new HashSet<>())
|
||||
.add(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
public Form putField(final String name, final Label label, final Label field) {
|
||||
this.formFields.put(name, createAccessor(label, field));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Form putField(final String name, final Label label, final Text field) {
|
||||
this.formFields.put(name, createAccessor(label, field));
|
||||
return this;
|
||||
}
|
||||
|
||||
public void putField(final String name, final Label label, final Combo field) {
|
||||
if (field instanceof SingleSelection) {
|
||||
this.formFields.put(name, createAccessor(label, (SingleSelection) field));
|
||||
}
|
||||
}
|
||||
|
||||
public void putSubForm(final String name, final Form form) {
|
||||
this.subForms.put(name, form);
|
||||
}
|
||||
|
||||
public Form getSubForm(final String name) {
|
||||
return this.subForms.get(name);
|
||||
}
|
||||
|
||||
public void addSubForm(final String arrayName, final Form form) {
|
||||
final List<Form> array = this.subLists.computeIfAbsent(arrayName, k -> new ArrayList<>());
|
||||
array.add(form);
|
||||
}
|
||||
|
||||
public Form getSubForm(final String arrayName, final int index) {
|
||||
final List<Form> array = this.subLists.get(arrayName);
|
||||
if (array == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return array.get(index);
|
||||
}
|
||||
|
||||
public void allVisible() {
|
||||
process(
|
||||
name -> true,
|
||||
ffa -> ffa.setVisible(true));
|
||||
}
|
||||
|
||||
public void setVisible(final boolean visible, final String group) {
|
||||
if (!this.groups.containsKey(group)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Set<String> namesSet = this.groups.get(group);
|
||||
process(
|
||||
name -> namesSet.contains(name),
|
||||
ffa -> ffa.setVisible(visible));
|
||||
}
|
||||
|
||||
public void process(
|
||||
final Predicate<String> nameFilter,
|
||||
final Consumer<FormFieldAccessor<?>> processor) {
|
||||
|
||||
this.formFields.entrySet()
|
||||
.stream()
|
||||
.filter(entity -> nameFilter.test(entity.getKey()))
|
||||
.map(entity -> entity.getValue())
|
||||
.forEach(processor);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
for (final Map.Entry<String, FormFieldAccessor<?>> entry : this.formFields.entrySet()) {
|
||||
final FormFieldAccessor<?> accessor = entry.getValue();
|
||||
if (accessor.control.isVisible()) {
|
||||
this.objectRoot.put(entry.getKey(), accessor.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
for (final Map.Entry<String, Form> entry : this.subForms.entrySet()) {
|
||||
final Form subForm = entry.getValue();
|
||||
subForm.flush();
|
||||
final ObjectNode objectNode = this.jsonMapper.createObjectNode();
|
||||
this.objectRoot.set(entry.getKey(), objectNode);
|
||||
}
|
||||
|
||||
for (final Map.Entry<String, List<Form>> entry : this.subLists.entrySet()) {
|
||||
final List<Form> value = entry.getValue();
|
||||
final ArrayNode arrayNode = this.jsonMapper.createArrayNode();
|
||||
final int index = 0;
|
||||
for (final Form arrayForm : value) {
|
||||
arrayForm.flush();
|
||||
arrayNode.insert(index, arrayForm.objectRoot);
|
||||
}
|
||||
this.objectRoot.set(entry.getKey(), arrayNode);
|
||||
}
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
private FormFieldAccessor<?> createAccessor(final Label label, final Label field) {
|
||||
return new FormFieldAccessor<>(label, field) {
|
||||
@Override public String getValue() { return field.getText(); }
|
||||
@Override public void setValue(final String value) { field.setText(value); }
|
||||
};
|
||||
}
|
||||
private FormFieldAccessor<Text> createAccessor(final Label label, final Text text) {
|
||||
return new FormFieldAccessor<>(label, text) {
|
||||
@Override public String getValue() { return text.getText(); }
|
||||
@Override public void setValue(final String value) { text.setText(value); }
|
||||
};
|
||||
}
|
||||
private FormFieldAccessor<SingleSelection> createAccessor(
|
||||
final Label label,
|
||||
final SingleSelection singleSelection) {
|
||||
|
||||
return new FormFieldAccessor<>(label, singleSelection) {
|
||||
@Override public String getValue() { return singleSelection.getSelectionValue(); }
|
||||
@Override public void setValue(final String value) { singleSelection.select(value); }
|
||||
};
|
||||
}
|
||||
//@formatter:on
|
||||
|
||||
public static abstract class FormFieldAccessor<T extends Control> {
|
||||
|
||||
public final Label label;
|
||||
public final T control;
|
||||
private boolean hasError;
|
||||
|
||||
public FormFieldAccessor(final Label label, final T control) {
|
||||
this.label = label;
|
||||
this.control = control;
|
||||
}
|
||||
|
||||
public abstract String getValue();
|
||||
|
||||
public abstract void setValue(String value);
|
||||
|
||||
public void setVisible(final boolean visible) {
|
||||
this.label.setVisible(visible);
|
||||
this.control.setVisible(visible);
|
||||
}
|
||||
|
||||
public void setError(final String errorTooltip) {
|
||||
if (!this.hasError) {
|
||||
this.control.setData(RWT.CUSTOM_VARIANT, "error");
|
||||
//this.control.setBackground(new Color(this.control.getDisplay(), 255, 0, 0, 50));
|
||||
this.control.setToolTipText(errorTooltip);
|
||||
this.hasError = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetError() {
|
||||
if (this.hasError) {
|
||||
this.control.setData(RWT.CUSTOM_VARIANT, null);
|
||||
//this.control.setBackground(new Color(this.control.getDisplay(), 0, 0, 0, 0));
|
||||
this.control.setToolTipText(null);
|
||||
this.hasError = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.page.form;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
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.Combo;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.TabItem;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
|
||||
public class FormBuilder {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FormBuilder.class);
|
||||
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final PolyglotPageService polyglotPageService;
|
||||
public final PageContext pageContext;
|
||||
public final Composite formParent;
|
||||
public final Form form;
|
||||
|
||||
private boolean readonly = false;
|
||||
|
||||
FormBuilder(
|
||||
final JSONMapper jsonMapper,
|
||||
final WidgetFactory widgetFactory,
|
||||
final PolyglotPageService polyglotPageService,
|
||||
final PageContext pageContext,
|
||||
final int rows) {
|
||||
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.polyglotPageService = polyglotPageService;
|
||||
this.pageContext = pageContext;
|
||||
this.form = new Form(jsonMapper);
|
||||
|
||||
this.formParent = new Composite(pageContext.getParent(), SWT.NONE);
|
||||
final GridLayout layout = new GridLayout(rows, true);
|
||||
layout.horizontalSpacing = 10;
|
||||
layout.verticalSpacing = 10;
|
||||
layout.marginLeft = 10;
|
||||
layout.marginTop = 10;
|
||||
this.formParent.setLayout(layout);
|
||||
this.formParent.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
}
|
||||
|
||||
public FormBuilder readonly(final boolean readonly) {
|
||||
this.readonly = readonly;
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormBuilder setVisible(final boolean visible, final String group) {
|
||||
this.form.setVisible(visible, group);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormBuilder setControl(final TabItem instTab) {
|
||||
instTab.setControl(this.formParent);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormBuilder addEmptyCell() {
|
||||
return addEmptyCell(1);
|
||||
}
|
||||
|
||||
public FormBuilder addEmptyCell(final int span) {
|
||||
this.widgetFactory.formEmpty(this.formParent, span, 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormBuilder putStaticValue(final String name, final String value) {
|
||||
try {
|
||||
this.form.putStatic(name, value);
|
||||
} catch (final Exception e) {
|
||||
log.error("Failed to put static field value to json object: ", e);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormBuilder addTextField(
|
||||
final String name,
|
||||
final String label,
|
||||
final String value) {
|
||||
|
||||
return addTextField(name, label, value, 1, null);
|
||||
}
|
||||
|
||||
public FormBuilder addTextField(
|
||||
final String name,
|
||||
final String label,
|
||||
final String value,
|
||||
final int span) {
|
||||
|
||||
return addTextField(name, label, value, span, null);
|
||||
}
|
||||
|
||||
public FormBuilder addTextField(
|
||||
final String name,
|
||||
final String label,
|
||||
final String value,
|
||||
final int span,
|
||||
final String group) {
|
||||
|
||||
final Label lab = this.widgetFactory.formLabelLocalized(this.formParent, label);
|
||||
if (this.readonly) {
|
||||
this.form.putField(name, lab, this.widgetFactory.formValueLabel(this.formParent, value, span));
|
||||
} else {
|
||||
this.form.putField(name, lab, this.widgetFactory.formTextInput(this.formParent, value, span, 1));
|
||||
}
|
||||
if (StringUtils.isNoneBlank(group)) {
|
||||
this.form.addToGroup(group, name);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public FormBuilder addSingleSelection(
|
||||
final String name,
|
||||
final String label,
|
||||
final String value,
|
||||
final List<Tuple<String>> items,
|
||||
final Consumer<Form> selectionListener) {
|
||||
|
||||
return addSingleSelection(name, label, value, items, selectionListener, 1, null);
|
||||
}
|
||||
|
||||
public FormBuilder addSingleSelection(
|
||||
final String name,
|
||||
final String label,
|
||||
final String value,
|
||||
final List<Tuple<String>> items,
|
||||
final Consumer<Form> selectionListener,
|
||||
final int span) {
|
||||
|
||||
return addSingleSelection(name, label, value, items, selectionListener, span, null);
|
||||
}
|
||||
|
||||
public FormBuilder addSingleSelection(
|
||||
final String name,
|
||||
final String label,
|
||||
final String value,
|
||||
final List<Tuple<String>> items,
|
||||
final Consumer<Form> selectionListener,
|
||||
final int span,
|
||||
final String group) {
|
||||
|
||||
final Label lab = this.widgetFactory.formLabelLocalized(this.formParent, label);
|
||||
if (this.readonly) {
|
||||
this.form.putField(name, lab, this.widgetFactory.formValueLabel(this.formParent, value, 2));
|
||||
} else {
|
||||
final Combo selection =
|
||||
this.widgetFactory.formSingleSelectionLocalized(this.formParent, value, items, span, 1);
|
||||
this.form.putField(name, lab, selection);
|
||||
if (selectionListener != null) {
|
||||
selection.addListener(SWT.Selection, e -> {
|
||||
selectionListener.accept(this.form);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNoneBlank(group)) {
|
||||
this.form.addToGroup(group, name);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> FormHandle<T> buildFor(final RestCall<T> post) {
|
||||
return new FormHandle<>(this.pageContext, this.form, post, this.polyglotPageService.getI18nSupport());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.page.form;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.form.Form.FormFieldAccessor;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.validation.FieldValidationError;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCallError;
|
||||
|
||||
public class FormHandle<T> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FormHandle.class);
|
||||
|
||||
public static final String FIELD_VALIDATION_LOCTEXT_PREFIX = "org.sebserver.form.validation.fieldError.";
|
||||
|
||||
private final PageContext pageContext;
|
||||
private final Form form;
|
||||
private final RestCall<T> post;
|
||||
private final I18nSupport i18nSupport;
|
||||
|
||||
FormHandle(
|
||||
final PageContext pageContext,
|
||||
final Form form,
|
||||
final RestCall<T> post,
|
||||
final I18nSupport i18nSupport) {
|
||||
|
||||
this.pageContext = pageContext;
|
||||
this.form = form;
|
||||
this.post = post;
|
||||
this.i18nSupport = i18nSupport;
|
||||
}
|
||||
|
||||
public void doAPIPost(final ActionDefinition action) {
|
||||
this.form.process(
|
||||
name -> true,
|
||||
fieldAccessor -> fieldAccessor.resetError());
|
||||
|
||||
this.post
|
||||
.newBuilder()
|
||||
.withFormBinding(this.form)
|
||||
.call()
|
||||
.map(result -> {
|
||||
this.pageContext.publishPageEvent(new ActionEvent(action, result));
|
||||
return result;
|
||||
}).onErrorDo(error -> {
|
||||
if (error instanceof RestCallError) {
|
||||
((RestCallError) error)
|
||||
.getErrorMessages()
|
||||
.stream()
|
||||
.map(FieldValidationError::new)
|
||||
.forEach(fve -> this.form.process(
|
||||
name -> name.equals(fve.fieldName),
|
||||
fieldAccessor -> showValidationError(fieldAccessor, fve)));
|
||||
} else {
|
||||
log.error("Unexpected error while trying to post form: ", error);
|
||||
this.pageContext.notifyError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private final void showValidationError(
|
||||
final FormFieldAccessor<?> fieldAccessor,
|
||||
final FieldValidationError valError) {
|
||||
|
||||
fieldAccessor.setError(this.i18nSupport.getText(new LocTextKey(
|
||||
FIELD_VALIDATION_LOCTEXT_PREFIX + valError.errorType,
|
||||
(Object[]) valError.attributes)));
|
||||
}
|
||||
|
||||
public FormHandle<T> process(final Consumer<Form> consumer) {
|
||||
consumer.accept(this.form);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.page.form;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
public class PageFormService {
|
||||
|
||||
private final JSONMapper jsonMapper;
|
||||
private final WidgetFactory widgetFactory;
|
||||
private final PolyglotPageService polyglotPageService;
|
||||
|
||||
public PageFormService(
|
||||
final JSONMapper jsonMapper,
|
||||
final WidgetFactory widgetFactory,
|
||||
final PolyglotPageService polyglotPageService) {
|
||||
|
||||
this.jsonMapper = jsonMapper;
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.polyglotPageService = polyglotPageService;
|
||||
}
|
||||
|
||||
public FormBuilder getBuilder(final PageContext pageContext, final int rows) {
|
||||
return new FormBuilder(
|
||||
this.jsonMapper,
|
||||
this.widgetFactory,
|
||||
this.polyglotPageService,
|
||||
pageContext,
|
||||
rows);
|
||||
}
|
||||
|
||||
public WidgetFactory getWidgetFactory() {
|
||||
return this.widgetFactory;
|
||||
}
|
||||
|
||||
public PolyglotPageService getPolyglotPageService() {
|
||||
return this.polyglotPageService;
|
||||
}
|
||||
|
||||
}
|
|
@ -20,13 +20,14 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.stereotype.Service;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.RWTUtils;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
|
||||
@Lazy
|
||||
@Service
|
||||
|
@ -40,17 +41,20 @@ public class ComposerServiceImpl implements ComposerService {
|
|||
private final Class<? extends PageDefinition> mainPageType = DefaultMainPage.class;
|
||||
|
||||
final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final RestService restService;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final Map<String, TemplateComposer> composer;
|
||||
private final Map<String, PageDefinition> pages;
|
||||
|
||||
public ComposerServiceImpl(
|
||||
final AuthorizationContextHolder authorizationContextHolder,
|
||||
final RestService restService,
|
||||
final I18nSupport i18nSupport,
|
||||
final Collection<TemplateComposer> composer,
|
||||
final Collection<PageDefinition> pageDefinitions) {
|
||||
|
||||
this.authorizationContextHolder = authorizationContextHolder;
|
||||
this.restService = restService;
|
||||
this.i18nSupport = i18nSupport;
|
||||
this.composer = composer
|
||||
.stream()
|
||||
|
@ -108,7 +112,7 @@ public class ComposerServiceImpl implements ComposerService {
|
|||
|
||||
if (composer.validate(pageContext)) {
|
||||
|
||||
RWTUtils.clearComposite(pageContext.getParent());
|
||||
WidgetFactory.clearComposite(pageContext.getParent());
|
||||
|
||||
try {
|
||||
composer.compose(pageContext);
|
||||
|
@ -169,8 +173,7 @@ public class ComposerServiceImpl implements ComposerService {
|
|||
}
|
||||
|
||||
private PageContext createPageContext(final Composite root) {
|
||||
return new PageContextImpl(
|
||||
this.i18nSupport, this, root, root, null);
|
||||
return new PageContextImpl(this.restService, this.i18nSupport, this, root, root, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import ch.ethz.seb.sebserver.gui.service.page.PageContext.AttributeKeys;
|
|||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.CustomVariant;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
|
@ -243,11 +244,17 @@ public class DefaultPageLayout implements TemplateComposer {
|
|||
rowLayout.marginRight = 20;
|
||||
footerRight.setLayout(rowLayout);
|
||||
|
||||
this.widgetFactory.labelLocalized(footerLeft, "footer", new LocTextKey("sebserver.overall.imprint"));
|
||||
this.widgetFactory.labelLocalized(footerLeft, "footer", new LocTextKey("sebserver.overall.about"));
|
||||
this.widgetFactory.labelLocalized(
|
||||
footerLeft,
|
||||
CustomVariant.FOOTER,
|
||||
new LocTextKey("sebserver.overall.imprint"));
|
||||
this.widgetFactory.labelLocalized(
|
||||
footerLeft,
|
||||
CustomVariant.FOOTER,
|
||||
new LocTextKey("sebserver.overall.about"));
|
||||
this.widgetFactory.labelLocalized(
|
||||
footerRight,
|
||||
"footer",
|
||||
CustomVariant.FOOTER,
|
||||
new LocTextKey("sebserver.overall.version", this.sebServerVersion));
|
||||
}
|
||||
|
||||
|
|
|
@ -29,8 +29,13 @@ import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport;
|
|||
import ch.ethz.seb.sebserver.gui.service.page.ComposerService;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageMessageException;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.Action;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.action.ActionDefinition;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitySelection;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.Message;
|
||||
|
||||
public class PageContextImpl implements PageContext {
|
||||
|
@ -39,6 +44,7 @@ public class PageContextImpl implements PageContext {
|
|||
|
||||
private static final ListenerComparator LIST_COMPARATOR = new ListenerComparator();
|
||||
|
||||
private final RestService restService;
|
||||
private final I18nSupport i18nSupport;
|
||||
private final ComposerService composerService;
|
||||
private final Composite root;
|
||||
|
@ -46,12 +52,14 @@ public class PageContextImpl implements PageContext {
|
|||
private final Map<String, String> attributes;
|
||||
|
||||
PageContextImpl(
|
||||
final RestService restService,
|
||||
final I18nSupport i18nSupport,
|
||||
final ComposerService composerService,
|
||||
final Composite root,
|
||||
final Composite parent,
|
||||
final Map<String, String> attributes) {
|
||||
|
||||
this.restService = restService;
|
||||
this.i18nSupport = i18nSupport;
|
||||
this.composerService = composerService;
|
||||
this.root = root;
|
||||
|
@ -86,6 +94,7 @@ public class PageContextImpl implements PageContext {
|
|||
@Override
|
||||
public PageContext copyOf(final Composite parent) {
|
||||
return new PageContextImpl(
|
||||
this.restService,
|
||||
this.i18nSupport,
|
||||
this.composerService,
|
||||
this.root,
|
||||
|
@ -99,6 +108,7 @@ public class PageContextImpl implements PageContext {
|
|||
attrs.putAll(this.attributes);
|
||||
attrs.putAll(((PageContextImpl) otherContext).attributes);
|
||||
return new PageContextImpl(
|
||||
this.restService,
|
||||
this.i18nSupport,
|
||||
this.composerService,
|
||||
this.root,
|
||||
|
@ -112,10 +122,31 @@ public class PageContextImpl implements PageContext {
|
|||
attrs.putAll(this.attributes);
|
||||
attrs.put(key, value);
|
||||
return new PageContextImpl(
|
||||
this.restService,
|
||||
this.i18nSupport,
|
||||
this.composerService,
|
||||
this.root,
|
||||
this.parent, attrs);
|
||||
this.parent,
|
||||
attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageContext withSelection(final ActivitySelection selection) {
|
||||
if (selection == null) {
|
||||
return this;
|
||||
}
|
||||
|
||||
final Map<String, String> attrs = new HashMap<>();
|
||||
attrs.putAll(this.attributes);
|
||||
attrs.putAll(selection.getAttributes());
|
||||
|
||||
return new PageContextImpl(
|
||||
this.restService,
|
||||
this.i18nSupport,
|
||||
this.composerService,
|
||||
this.root,
|
||||
this.parent,
|
||||
attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -160,6 +191,11 @@ public class PageContextImpl implements PageContext {
|
|||
.forEach(listener -> listener.notify(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action createAction(final ActionDefinition actionDefinition) {
|
||||
return new Action(actionDefinition, this, this.restService);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("serial")
|
||||
public void applyConfirmDialog(final String confirmMessage, final Runnable onOK) {
|
||||
|
@ -212,6 +248,17 @@ public class PageContextImpl implements PageContext {
|
|||
forwardToPage(this.composerService.loginPage(), pageContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void publishPageMessage(final PageMessageException pme) {
|
||||
final MessageBox messageBox = new Message(
|
||||
getShell(),
|
||||
this.i18nSupport.getText("sebserver.page.message"),
|
||||
this.i18nSupport.getText(pme.getMessage()),
|
||||
SWT.NONE);
|
||||
messageBox.setMarkupEnabled(true);
|
||||
messageBox.open(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyError(final String errorMessage, final Throwable error) {
|
||||
if (error instanceof APIMessageError) {
|
||||
|
|
|
@ -60,8 +60,8 @@ public class SEBLogin implements TemplateComposer {
|
|||
if (pageContext.hasAttribute((AttributeKeys.LGOUT_SUCCESS))) {
|
||||
final MessageBox logoutSuccess = new Message(
|
||||
pageContext.getShell(),
|
||||
this.i18nSupport.getText("org.sebserver.logout"),
|
||||
this.i18nSupport.getText("org.sebserver.logout.success.message"),
|
||||
this.i18nSupport.getText("sebserver.logout"),
|
||||
this.i18nSupport.getText("sebserver.logout.success.message"),
|
||||
SWT.ICON_INFORMATION);
|
||||
logoutSuccess.open(null);
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ import org.springframework.stereotype.Component;
|
|||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageContext;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.TemplateComposer;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.activity.ActivitiesPane;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionEvent;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.ActivitySelectionListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.page.event.PageEventListener;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory.IconButtonType;
|
||||
|
||||
|
@ -128,9 +128,9 @@ public class SEBMainPage implements TemplateComposer {
|
|||
public void notify(final ActivitySelectionEvent event) {
|
||||
pageContext.composerService().compose(
|
||||
event.selection.activity.contentPaneComposer,
|
||||
pageContext.copyOf(contentObjects).withAttr(
|
||||
event.selection.activity.objectIdentifierAttribute,
|
||||
event.selection.getObjectIdentifier()));
|
||||
pageContext
|
||||
.copyOf(contentObjects)
|
||||
.withSelection(event.selection));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -150,9 +150,9 @@ public class SEBMainPage implements TemplateComposer {
|
|||
public void notify(final ActivitySelectionEvent event) {
|
||||
pageContext.composerService().compose(
|
||||
event.selection.activity.actionPaneComposer,
|
||||
pageContext.copyOf(actionPane).withAttr(
|
||||
event.selection.activity.objectIdentifierAttribute,
|
||||
event.selection.getObjectIdentifier()));
|
||||
pageContext
|
||||
.copyOf(actionPane)
|
||||
.withSelection(event.selection));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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.page.validation;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||
|
||||
public class FieldValidationError {
|
||||
|
||||
public final String messageCode;
|
||||
public final String domainName;
|
||||
public final String fieldName;
|
||||
public final String errorType;
|
||||
public final String[] attributes;
|
||||
|
||||
public FieldValidationError(final APIMessage apiMessage) {
|
||||
this(
|
||||
apiMessage.messageCode,
|
||||
apiMessage.attributes.toArray(new String[apiMessage.attributes.size()]));
|
||||
}
|
||||
|
||||
public FieldValidationError(
|
||||
final String messageCode,
|
||||
final String[] attributes) {
|
||||
|
||||
this.messageCode = messageCode;
|
||||
this.attributes = attributes;
|
||||
|
||||
this.domainName = (attributes != null && attributes.length > 0) ? attributes[0] : null;
|
||||
this.fieldName = (attributes != null && attributes.length > 1) ? attributes[1] : null;
|
||||
this.errorType = (attributes != null && attributes.length > 2) ? attributes[2] : null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api;
|
||||
|
||||
public interface FormBinding {
|
||||
|
||||
String getFormAsJson();
|
||||
|
||||
}
|
|
@ -66,6 +66,9 @@ public abstract class RestCall<T> {
|
|||
}
|
||||
|
||||
protected Result<T> exchange(final RestCallBuilder builder) {
|
||||
|
||||
log.debug("Call webservice API on {} for {}", this.path, builder);
|
||||
|
||||
try {
|
||||
final ResponseEntity<String> responseEntity = RestCall.this.restService
|
||||
.getWebserviceAPIRestTemplate()
|
||||
|
@ -90,6 +93,11 @@ public abstract class RestCall<T> {
|
|||
responseEntity.getBody(),
|
||||
new TypeReference<List<APIMessage>>() {
|
||||
}));
|
||||
|
||||
log.debug(
|
||||
"Webservice answered with well defined error- or validation-failure-response: ",
|
||||
restCallError);
|
||||
|
||||
return Result.ofError(restCallError);
|
||||
}
|
||||
|
||||
|
@ -102,7 +110,7 @@ public abstract class RestCall<T> {
|
|||
new TypeReference<List<APIMessage>>() {
|
||||
}));
|
||||
} catch (final Exception e) {
|
||||
log.error("Unable to handle rest call error: ", e);
|
||||
log.error("Unexpected error-response while webservice API call for: {}", builder, e);
|
||||
}
|
||||
|
||||
return Result.ofError(restCallError);
|
||||
|
@ -180,6 +188,11 @@ public abstract class RestCall<T> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public RestCallBuilder withFormBinding(final FormBinding formBinding) {
|
||||
// TODO Auto-generated method stub
|
||||
return this;
|
||||
}
|
||||
|
||||
public RestCallBuilder onlyActive(final boolean active) {
|
||||
this.queryParams.put(Entity.FILTER_ATTR_ACTIVE, Arrays.asList(String.valueOf(active)));
|
||||
return this;
|
||||
|
@ -204,6 +217,13 @@ public abstract class RestCall<T> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestCallBuilder [httpHeaders=" + this.httpHeaders + ", body=" + this.body + ", queryParams="
|
||||
+ this.queryParams
|
||||
+ ", uriVariables=" + this.uriVariables + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,4 +37,8 @@ public class RestCallError extends RuntimeException implements APIMessageError {
|
|||
return !this.errors.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "RestCallError [errors=" + this.errors + "]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,8 +12,6 @@ import java.util.Collection;
|
|||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
@ -29,8 +27,6 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURISer
|
|||
@GuiProfile
|
||||
public class RestService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(RestService.class);
|
||||
|
||||
private final AuthorizationContextHolder authorizationContextHolder;
|
||||
private final WebserviceURIService webserviceURIBuilderSupplier;
|
||||
private final Map<String, RestCall<?>> calls;
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class GetInstitution extends RestCall<Institution> {
|
||||
|
||||
protected GetInstitution() {
|
||||
super(
|
||||
new TypeReference<Institution>() {
|
||||
},
|
||||
HttpMethod.GET,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
SEBServerRestEndpoints.ENDPOINT_INSTITUTION);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution;
|
||||
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints;
|
||||
import ch.ethz.seb.sebserver.gbl.model.institution.Institution;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall;
|
||||
|
||||
@Lazy
|
||||
@Component
|
||||
@GuiProfile
|
||||
public class NewInstitution extends RestCall<Institution> {
|
||||
|
||||
protected NewInstitution() {
|
||||
super(
|
||||
new TypeReference<Institution>() {
|
||||
},
|
||||
HttpMethod.POST,
|
||||
MediaType.APPLICATION_FORM_URLENCODED,
|
||||
SEBServerRestEndpoints.ENDPOINT_INSTITUTION);
|
||||
}
|
||||
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.remote.webservice.auth;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -25,9 +26,11 @@ import org.springframework.http.HttpMethod;
|
|||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
|
||||
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
|
||||
import org.springframework.security.oauth2.client.http.OAuth2ErrorHandler;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2AccessDeniedException;
|
||||
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
|
||||
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
|
||||
|
@ -162,6 +165,14 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
|||
|
||||
this.restTemplate = new DisposableOAuth2RestTemplate(this.resource);
|
||||
this.restTemplate.setRequestFactory(clientHttpRequestFactory);
|
||||
this.restTemplate.setErrorHandler(new OAuth2ErrorHandler(this.resource) {
|
||||
@Override
|
||||
public boolean hasError(final ClientHttpResponse response) throws IOException {
|
||||
final HttpStatus statusCode = HttpStatus.resolve(response.getRawStatusCode());
|
||||
return (statusCode != null && statusCode.series() == HttpStatus.Series.SERVER_ERROR);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
this.revokeTokenURI = webserviceURIService.getOAuthRevokeTokenURI();
|
||||
this.currentUserURI = webserviceURIService.getCurrentUserRequestURI();
|
||||
|
|
|
@ -40,6 +40,15 @@ public final class ColumnDefinition<ROW extends Entity> {
|
|||
this(columnName, displayName, null, widthPercent, null, null, false);
|
||||
}
|
||||
|
||||
public ColumnDefinition(
|
||||
final String columnName,
|
||||
final LocTextKey displayName,
|
||||
final Function<ROW, Object> valueSupplier,
|
||||
final boolean sortable) {
|
||||
|
||||
this(columnName, displayName, null, -1, valueSupplier, null, sortable);
|
||||
}
|
||||
|
||||
public ColumnDefinition(
|
||||
final String columnName,
|
||||
final LocTextKey displayName,
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
|
||||
package ch.ethz.seb.sebserver.gui.service.table;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
|
@ -46,8 +50,6 @@ public class EntityTable<ROW extends Entity> extends Composite {
|
|||
private final Table table;
|
||||
private final TableNavigator navigator;
|
||||
|
||||
private final boolean selectableRows;
|
||||
|
||||
private int pageNumber = 1;
|
||||
private int pageSize;
|
||||
private String sortColumn = null;
|
||||
|
@ -56,31 +58,34 @@ public class EntityTable<ROW extends Entity> extends Composite {
|
|||
private boolean columnsWithSameWidth = true;
|
||||
|
||||
EntityTable(
|
||||
final int type,
|
||||
final Composite parent,
|
||||
final RestCall<Page<ROW>> restCall,
|
||||
final WidgetFactory widgetFactory,
|
||||
final List<ColumnDefinition<ROW>> columns,
|
||||
final List<TableRowAction> actions,
|
||||
final int pageSize,
|
||||
final boolean withFilter,
|
||||
final boolean selectableRows) {
|
||||
final boolean withFilter) {
|
||||
|
||||
super(parent, SWT.NONE);
|
||||
super(parent, type);
|
||||
this.widgetFactory = widgetFactory;
|
||||
this.restCall = restCall;
|
||||
this.columns = Utils.immutableListOf(columns);
|
||||
this.actions = Utils.immutableListOf(actions);
|
||||
|
||||
super.setLayout(new GridLayout());
|
||||
super.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
|
||||
GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
|
||||
|
||||
gridData.heightHint = (pageSize + 1) * 40;
|
||||
super.setLayoutData(gridData);
|
||||
|
||||
this.pageSize = pageSize;
|
||||
this.filter = (withFilter) ? new TableFilter<>(this) : null;
|
||||
this.selectableRows = selectableRows;
|
||||
|
||||
this.table = widgetFactory.tableLocalized(this);
|
||||
this.table.setLayout(new GridLayout(columns.size(), true));
|
||||
final GridData gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
gridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
|
||||
gridData.heightHint = (pageSize + 1) * 25;
|
||||
this.table.setLayoutData(gridData);
|
||||
this.table.addListener(SWT.Resize, this::adaptColumnWidth);
|
||||
|
||||
|
@ -148,6 +153,18 @@ public class EntityTable<ROW extends Entity> extends Composite {
|
|||
this.sortOrder);
|
||||
}
|
||||
|
||||
public Collection<String> getSelection() {
|
||||
final TableItem[] selection = this.table.getSelection();
|
||||
if (selection == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return Arrays.asList(selection)
|
||||
.stream()
|
||||
.map(this::getRowDataId)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void createTableColumns() {
|
||||
for (final ColumnDefinition<ROW> column : this.columns) {
|
||||
final TableColumn tableColumn = this.widgetFactory.tableColumnLocalized(
|
||||
|
@ -204,9 +221,6 @@ public class EntityTable<ROW extends Entity> extends Composite {
|
|||
final TableItem item = new TableItem(this.table, SWT.NONE);
|
||||
item.setData(TABLE_ROW_DATA, row);
|
||||
int index = 0;
|
||||
if (this.selectableRows) {
|
||||
// TODO
|
||||
}
|
||||
for (final ColumnDefinition<ROW> column : this.columns) {
|
||||
final Object value = column.valueSupplier.apply(row);
|
||||
if (value instanceof Boolean) {
|
||||
|
@ -247,4 +261,13 @@ public class EntityTable<ROW extends Entity> extends Composite {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private ROW getRowData(final TableItem item) {
|
||||
return (ROW) item.getData(TABLE_ROW_DATA);
|
||||
}
|
||||
|
||||
private String getRowDataId(final TableItem item) {
|
||||
return getRowData(item).getModelId();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gui.service.table;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||
|
@ -41,7 +42,7 @@ public class TableBuilder<ROW extends Entity> {
|
|||
final List<TableRowAction> actions = new ArrayList<>();
|
||||
|
||||
private int pageSize = -1;
|
||||
private boolean selectableRows = false;
|
||||
private int type = SWT.NONE;
|
||||
|
||||
public TableBuilder(
|
||||
final WidgetFactory widgetFactory,
|
||||
|
@ -61,13 +62,13 @@ public class TableBuilder<ROW extends Entity> {
|
|||
return this;
|
||||
}
|
||||
|
||||
public TableBuilder<ROW> withSelectableRows() {
|
||||
this.selectableRows = true;
|
||||
public TableBuilder<ROW> withAction(final TableRowAction action) {
|
||||
this.actions.add(action);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TableBuilder<ROW> withAction(final TableRowAction action) {
|
||||
this.actions.add(action);
|
||||
public TableBuilder<ROW> withMultiselection() {
|
||||
this.type |= SWT.MULTI;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -79,14 +80,14 @@ public class TableBuilder<ROW extends Entity> {
|
|||
.isPresent();
|
||||
|
||||
return new EntityTable<>(
|
||||
this.type,
|
||||
parent,
|
||||
this.restCall,
|
||||
this.widgetFactory,
|
||||
this.columns,
|
||||
this.actions,
|
||||
this.pageSize,
|
||||
withFilter,
|
||||
this.selectableRows);
|
||||
withFilter);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.eclipse.swt.widgets.Composite;
|
|||
import org.eclipse.swt.widgets.Label;
|
||||
|
||||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gui.service.RWTUtils;
|
||||
import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory;
|
||||
|
||||
public class TableNavigator extends Composite {
|
||||
|
||||
|
@ -39,7 +39,7 @@ public class TableNavigator extends Composite {
|
|||
|
||||
public Page<?> update(final Page<?> pageData) {
|
||||
// clear all
|
||||
RWTUtils.clearComposite(this);
|
||||
WidgetFactory.clearComposite(this);
|
||||
|
||||
final int pageNumber = pageData.getPageNumber();
|
||||
final int numberOfPages = pageData.getNumberOfPages();
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.eclipse.swt.layout.GridData;
|
|||
import org.eclipse.swt.widgets.Button;
|
||||
import org.eclipse.swt.widgets.Combo;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Label;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Table;
|
||||
|
@ -42,7 +43,6 @@ import ch.ethz.seb.sebserver.gbl.model.Entity;
|
|||
import ch.ethz.seb.sebserver.gbl.model.Page;
|
||||
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||
import ch.ethz.seb.sebserver.gbl.util.Tuple;
|
||||
import ch.ethz.seb.sebserver.gui.service.RWTUtils;
|
||||
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.i18n.PolyglotPageService;
|
||||
|
@ -57,9 +57,27 @@ public class WidgetFactory {
|
|||
|
||||
private static final Logger log = LoggerFactory.getLogger(WidgetFactory.class);
|
||||
|
||||
public enum CustomVariant {
|
||||
TEXT_H1("h1"),
|
||||
TEXT_H2("h2"),
|
||||
TEXT_H3("h3"),
|
||||
TEXT_ACTION("action"),
|
||||
|
||||
FOOTER("footer"),
|
||||
|
||||
;
|
||||
|
||||
public final String key;
|
||||
|
||||
private CustomVariant(final String key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
|
||||
public enum IconButtonType {
|
||||
MAXIMIZE("maximize.png"),
|
||||
MINIMIZE("minimize.png"),
|
||||
MODIFY_ACTION("editAction.png"),
|
||||
SAVE_ACTION("saveAction.png"),
|
||||
NEW_ACTION("newAction.png"),
|
||||
DELETE_ACTION("deleteAction.png"),
|
||||
|
@ -108,10 +126,10 @@ public class WidgetFactory {
|
|||
return button;
|
||||
}
|
||||
|
||||
public Button buttonLocalized(final Composite parent, final String style, final String locTextKey) {
|
||||
public Button buttonLocalized(final Composite parent, final CustomVariant variant, final String locTextKey) {
|
||||
final Button button = new Button(parent, SWT.NONE);
|
||||
this.injectI18n(button, new LocTextKey(locTextKey));
|
||||
button.setData(RWT.CUSTOM_VARIANT, style);
|
||||
button.setData(RWT.CUSTOM_VARIANT, variant.key);
|
||||
return button;
|
||||
}
|
||||
|
||||
|
@ -133,10 +151,10 @@ public class WidgetFactory {
|
|||
return label;
|
||||
}
|
||||
|
||||
public Label labelLocalized(final Composite parent, final String style, final LocTextKey locTextKey) {
|
||||
public Label labelLocalized(final Composite parent, final CustomVariant variant, final LocTextKey locTextKey) {
|
||||
final Label label = new Label(parent, SWT.NONE);
|
||||
this.injectI18n(label, locTextKey);
|
||||
label.setData(RWT.CUSTOM_VARIANT, style);
|
||||
label.setData(RWT.CUSTOM_VARIANT, variant.key);
|
||||
return label;
|
||||
}
|
||||
|
||||
|
@ -152,24 +170,24 @@ public class WidgetFactory {
|
|||
|
||||
public Label labelLocalized(
|
||||
final Composite parent,
|
||||
final String style,
|
||||
final CustomVariant variant,
|
||||
final LocTextKey locTextKey,
|
||||
final LocTextKey locToolTextKey) {
|
||||
|
||||
final Label label = new Label(parent, SWT.NONE);
|
||||
this.injectI18n(label, locTextKey, locToolTextKey);
|
||||
label.setData(RWT.CUSTOM_VARIANT, style);
|
||||
label.setData(RWT.CUSTOM_VARIANT, variant.key);
|
||||
return label;
|
||||
}
|
||||
|
||||
public Label labelLocalizedTitle(final Composite content, final LocTextKey locTextKey) {
|
||||
final Label labelLocalized = labelLocalized(content, RWTUtils.TEXT_NAME_H2, locTextKey);
|
||||
final Label labelLocalized = labelLocalized(content, CustomVariant.TEXT_H1, locTextKey);
|
||||
labelLocalized.setLayoutData(new GridData(SWT.TOP, SWT.LEFT, true, false));
|
||||
return labelLocalized;
|
||||
}
|
||||
|
||||
public Tree treeLocalized(final Composite parent, final int style) {
|
||||
final Tree tree = new Tree(parent, SWT.SINGLE | SWT.FULL_SELECTION);
|
||||
final Tree tree = new Tree(parent, style);
|
||||
this.injectI18n(tree);
|
||||
return tree;
|
||||
}
|
||||
|
@ -381,6 +399,16 @@ public class WidgetFactory {
|
|||
}
|
||||
}
|
||||
|
||||
public static void clearComposite(final Composite parent) {
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (final Control control : parent.getChildren()) {
|
||||
control.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static Consumer<Tree> treeFunction(final I18nSupport i18nSupport) {
|
||||
return tree -> updateLocale(tree.getItems(), i18nSupport);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@ sebserver.login.pwd=Password
|
|||
sebserver.login.login=Sign In
|
||||
sebserver.login.failed.title=Login Failed
|
||||
sebserver.login.failed.message=Access Denied: Wrong username or password
|
||||
sebserver.logout=Sign out
|
||||
sebserver.logout.success.message=You have been successfully signed out.
|
||||
|
||||
################################
|
||||
# Main Page
|
||||
|
@ -29,6 +31,7 @@ sebserver.actionpane.title=Actions
|
|||
sebserver.activities.inst=Institution
|
||||
|
||||
sebserver.error.unexpected=Unexpected Error
|
||||
sebserver.page.message=Information
|
||||
|
||||
|
||||
################################
|
||||
|
@ -38,4 +41,14 @@ sebserver.error.unexpected=Unexpected Error
|
|||
sebserver.institution.list.title=Institutions
|
||||
sebserver.institution.list.column.name=Name
|
||||
sebserver.institution.list.column.urlSuffix=URL Suffix
|
||||
sebserver.institution.list.column.active=Active
|
||||
sebserver.institution.list.column.active=Active
|
||||
sebserver.institution.action.new=New Institution
|
||||
sebserver.institution.action.modify=Edit Institution
|
||||
sebserver.institution.action.delete=Delete Institution
|
||||
sebserver.institution.info.pleaseSelect=Please Select an Institution from the Table first.
|
||||
|
||||
################################
|
||||
# Form validation
|
||||
################################
|
||||
|
||||
sebserver.form.validation.fieldError.size=The size must be between {3} and {4}
|
BIN
src/main/resources/static/images/delete.png
Normal file
BIN
src/main/resources/static/images/delete.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 186 B |
BIN
src/main/resources/static/images/editAction.png
Normal file
BIN
src/main/resources/static/images/editAction.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 165 B |
Binary file not shown.
Before Width: | Height: | Size: 165 B After Width: | Height: | Size: 121 B |
Loading…
Reference in a new issue