diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java index 75a9cea1..a36e1277 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java @@ -16,6 +16,7 @@ public final class Constants { public static final Character LIST_SEPARATOR_CHAR = ','; public static final String LIST_SEPARATOR = ","; + public static final String EMPTY_NOTE = "--"; /** Date-Time formatter without milliseconds using UTC time-zone. Pattern is yyyy-MM-dd HH:mm:ss */ public static final DateTimeFormatter DATE_TIME_PATTERN_UTC_NO_MILLIS = DateTimeFormat diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/SEBServerRestEndpoints.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/SEBServerRestEndpoints.java index 4fbe08d2..6e6403fa 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/SEBServerRestEndpoints.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/SEBServerRestEndpoints.java @@ -22,4 +22,6 @@ public class SEBServerRestEndpoints { public static final String ENDPOINT_USER_ACTIVITY_LOG = "/useractivity"; + public static final String NAMES_ENDPOINT_SUFFIX = "/names"; + } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Page.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Page.java index b007a558..0e97a19b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/Page.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/Page.java @@ -51,16 +51,16 @@ public final class Page { this.sort = sort; } - public Integer getNumberOfPages() { - return this.numberOfPages; + public int getNumberOfPages() { + return (this.numberOfPages != null) ? this.numberOfPages : 1; } - public Integer getPageNumber() { - return this.pageNumber; + public int getPageNumber() { + return (this.pageNumber != null) ? this.pageNumber : 0; } - public Integer getPageSize() { - return this.pageSize; + public int getPageSize() { + return (this.pageSize != null) ? this.pageSize : -1; } public Collection getContent() { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/RWTUtils.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/RWTUtils.java new file mode 100644 index 00000000..3dfbf2df --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/RWTUtils.java @@ -0,0 +1,28 @@ +/* + * 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(); + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/PolyglotPageService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/PolyglotPageService.java index 9474b76b..0dd7b839 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/PolyglotPageService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/i18n/PolyglotPageService.java @@ -16,21 +16,22 @@ public interface PolyglotPageService { String POLYGLOT_WIDGET_FUNCTION_KEY = "POLYGLOT_WIDGET_FUNCTION"; String POLYGLOT_TREE_ITEM_TEXT_DATA_KEY = "POLYGLOT_TREE_ITEM_TEXT_DATA"; + String POLYGLOT_TREE_ITEM_TOOLTIP_DATA_KEY = "POLYGLOT_TREE_ITEM_TOOLTIP_DATA"; /** Gets the underling I18nSupport - * + * * @return the underling I18nSupport */ I18nSupport getI18nSupport(); /** The default locale for the page. * Uses I18nSupport.getCurrentLocale to do so. - * + * * @param root the root Composite of the page to change the language */ void setDefaultPageLocale(Composite root); /** Sets the given Locale and if needed, updates the page language according to the * given Locale - * + * * @param root root the root Composite of the page to change the language * @param locale the Locale to set */ void setPageLocale(Composite root, Locale locale); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/TemplateComposer.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/TemplateComposer.java index 79a640d8..537dce28 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/TemplateComposer.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/TemplateComposer.java @@ -10,10 +10,10 @@ package ch.ethz.seb.sebserver.gui.service.page; public interface TemplateComposer { - default boolean validate(final PageContext context) { + default boolean validate(final PageContext pageContext) { return true; } - void compose(PageContext composerCtx); + void compose(PageContext pageContext); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java index 8dff9ad6..fa0d9b03 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/activity/ActivitySelection.java @@ -17,6 +17,7 @@ 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; import ch.ethz.seb.sebserver.gui.service.page.action.ActionPane; +import ch.ethz.seb.sebserver.gui.service.page.content.InstitutionList; import ch.ethz.seb.sebserver.gui.service.page.impl.TODOTemplate; public class ActivitySelection { @@ -31,7 +32,7 @@ public class ActivitySelection { public enum Activity { NONE(TODOTemplate.class, TODOTemplate.class, (String) null), INSTITUTION_ROOT( - TODOTemplate.class, + InstitutionList.class, ActionPane.class, new LocTextKey("sebserver.activities.inst")), INSTITUTION_NODE( diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionList.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionList.java new file mode 100644 index 00000000..8c2dd599 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/content/InstitutionList.java @@ -0,0 +1,86 @@ +/* + * 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; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Component; + +import ch.ethz.seb.sebserver.gbl.model.Domain; +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.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.widget.WidgetFactory; + +@Lazy +@Component +@GuiProfile +public class InstitutionList implements TemplateComposer { + + private final WidgetFactory widgetFactory; + private final RestService restService; + + protected InstitutionList( + final WidgetFactory widgetFactory, + final RestService restService) { + + this.widgetFactory = widgetFactory; + this.restService = restService; + } + + @Override + public void compose(final PageContext pageContext) { + final Composite content = new Composite(pageContext.getParent(), SWT.NONE); + final GridLayout contentLayout = new GridLayout(); + contentLayout.marginLeft = 10; + content.setLayout(contentLayout); + content.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + 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); + + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java index 8c76d3ac..49b307c3 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/page/impl/ComposerServiceImpl.java @@ -14,13 +14,13 @@ import java.util.function.Function; import java.util.stream.Collectors; import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; import org.slf4j.Logger; import org.slf4j.LoggerFactory; 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; @@ -108,7 +108,7 @@ public class ComposerServiceImpl implements ComposerService { if (composer.validate(pageContext)) { - clear(pageContext.getParent()); + RWTUtils.clearComposite(pageContext.getParent()); try { composer.compose(pageContext); @@ -173,14 +173,4 @@ public class ComposerServiceImpl implements ComposerService { this.i18nSupport, this, root, root, null); } - private void clear(final Composite parent) { - if (parent == null) { - return; - } - - for (final Control control : parent.getChildren()) { - control.dispose(); - } - } - } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FilterAttributeSupplier.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FilterAttributeSupplier.java new file mode 100644 index 00000000..33f1057b --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/FilterAttributeSupplier.java @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gui.service.remote.webservice.api; + +import org.springframework.util.MultiValueMap; + +public interface FilterAttributeSupplier { + + MultiValueMap getAttributes(); + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java index 2a8b1dd4..cb3f84f0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/RestCall.java @@ -30,6 +30,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.JSONMapper; +import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder; @@ -166,7 +167,21 @@ public abstract class RestCall { } public RestCallBuilder withSorting(final String column, final SortOrder order) { - this.queryParams.put(Page.ATTR_SORT, Arrays.asList(order.prefix + column)); + if (column != null) { + this.queryParams.put(Page.ATTR_SORT, Arrays.asList(order.encode(column))); + } + return this; + } + + public RestCallBuilder withFilterAttributes(final FilterAttributeSupplier filterAttributes) { + if (filterAttributes != null) { + this.queryParams.putAll(filterAttributes.getAttributes()); + } + return this; + } + + public RestCallBuilder onlyActive(final boolean active) { + this.queryParams.put(Entity.FILTER_ATTR_ACTIVE, Arrays.asList(String.valueOf(active))); return this; } @@ -188,6 +203,7 @@ public abstract class RestCall { return new HttpEntity<>(this.httpHeaders); } } + } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutionNames.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutionNames.java index 9f0f9969..8c0e0bee 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutionNames.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutionNames.java @@ -33,7 +33,13 @@ public class GetInstitutionNames extends RestCall> { }, HttpMethod.GET, MediaType.APPLICATION_FORM_URLENCODED, - SEBServerRestEndpoints.ENDPOINT_INSTITUTION + "/names"); + SEBServerRestEndpoints.ENDPOINT_INSTITUTION + SEBServerRestEndpoints.NAMES_ENDPOINT_SUFFIX); + } + + @Override + public RestCall>.RestCallBuilder newBuilder() { + return super.newBuilder() + .onlyActive(true); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutions.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutions.java new file mode 100644 index 00000000..62bf1cb6 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/remote/webservice/api/institution/GetInstitutions.java @@ -0,0 +1,38 @@ +/* + * 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.Page; +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 GetInstitutions extends RestCall> { + + protected GetInstitutions() { + super( + new TypeReference>() { + }, + HttpMethod.GET, + MediaType.APPLICATION_FORM_URLENCODED, + SEBServerRestEndpoints.ENDPOINT_INSTITUTION); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/ColumnDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/ColumnDefinition.java new file mode 100644 index 00000000..6684522e --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/ColumnDefinition.java @@ -0,0 +1,60 @@ +/* + * 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.table; + +import java.util.function.Function; + +import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; + +public final class ColumnDefinition { + + final String columnName; + final LocTextKey displayName; + final LocTextKey tooltip; + final int widthPercent; + final Function valueSupplier; + final ColumnFilterDefinition filter; + final boolean sortable; + + public ColumnDefinition( + final String columnName, + final LocTextKey displayName, + final LocTextKey tooltip, + final int widthPercent) { + + this(columnName, displayName, tooltip, widthPercent, null, null, false); + } + + public ColumnDefinition( + final String columnName, + final LocTextKey displayName, + final int widthPercent) { + + this(columnName, displayName, null, widthPercent, null, null, false); + } + + public ColumnDefinition( + final String columnName, + final LocTextKey displayName, + final LocTextKey tooltip, + final int widthPercent, + final Function valueSupplier, + final ColumnFilterDefinition filter, + final boolean sortable) { + + this.columnName = columnName; + this.displayName = displayName; + this.tooltip = tooltip; + this.widthPercent = widthPercent; + this.valueSupplier = valueSupplier; + this.filter = filter; + this.sortable = sortable; + } +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/ColumnFilterDefinition.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/ColumnFilterDefinition.java new file mode 100644 index 00000000..e89743e8 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/ColumnFilterDefinition.java @@ -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.table; + +public class ColumnFilterDefinition { + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/EntityTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/EntityTable.java new file mode 100644 index 00000000..e664473c --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/EntityTable.java @@ -0,0 +1,250 @@ +/* + * 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.table; + +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.TableItem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; +import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory; +import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService.SortOrder; + +public class EntityTable extends Composite { + + private static final Logger log = LoggerFactory.getLogger(EntityTable.class); + + private static final long serialVersionUID = -4931198225547108993L; + + public static final String TABLE_ROW_DATA = "TABLE_ROW_DATA"; + + private final WidgetFactory widgetFactory; + + private final RestCall> restCall; + private final List> columns; + private final List actions; + + private final TableFilter filter; + private final Table table; + private final TableNavigator navigator; + + private final boolean selectableRows; + + private int pageNumber = 1; + private int pageSize; + private String sortColumn = null; + private SortOrder sortOrder = SortOrder.ASCENDING; + + private boolean columnsWithSameWidth = true; + + EntityTable( + final Composite parent, + final RestCall> restCall, + final WidgetFactory widgetFactory, + final List> columns, + final List actions, + final int pageSize, + final boolean withFilter, + final boolean selectableRows) { + + super(parent, SWT.NONE); + 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)); + + 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); + this.table.setLayoutData(gridData); + this.table.addListener(SWT.Resize, this::adaptColumnWidth); + + //this.table.setLayoutData(new GridData(GridData.FILL_BOTH)); + this.table.setHeaderVisible(true); + this.table.setLinesVisible(true); + + this.navigator = new TableNavigator(this); + + createTableColumns(); + updateTableRows( + this.pageNumber, + this.pageSize, + this.sortColumn, + this.sortOrder); + } + + public void setPageSize(final int pageSize) { + this.pageSize = pageSize; + updateTableRows( + this.pageNumber, + this.pageSize, + this.sortColumn, + this.sortOrder); + } + + public void selectPage(final int pageSelection) { + // verify input + this.pageNumber = pageSelection; + if (this.pageNumber < 1) { + this.pageNumber = 1; + } + + updateTableRows( + this.pageNumber, + this.pageSize, + this.sortColumn, + this.sortOrder); + } + + public void applyFilter() { + // TODO remove all rows, set current page to 0, call rest to get entities and build rows and navigation again + } + + public void applySort(final String columnName) { + this.sortColumn = columnName; + this.sortOrder = SortOrder.ASCENDING; + + updateTableRows( + this.pageNumber, + this.pageSize, + this.sortColumn, + this.sortOrder); + } + + public void changeSortOrder() { + this.sortOrder = (this.sortOrder == SortOrder.ASCENDING) + ? SortOrder.DESCENDING + : SortOrder.ASCENDING; + + updateTableRows( + this.pageNumber, + this.pageSize, + this.sortColumn, + this.sortOrder); + } + + private void createTableColumns() { + for (final ColumnDefinition column : this.columns) { + final TableColumn tableColumn = this.widgetFactory.tableColumnLocalized( + this.table, + column.displayName, + column.tooltip); + + if (column.sortable) { + tableColumn.addListener(SWT.Selection, event -> { + if (!column.columnName.equals(this.sortColumn)) { + applySort(column.columnName); + this.table.setSortColumn(tableColumn); + this.table.setSortDirection(SWT.UP); + } else { + changeSortOrder(); + this.table.setSortDirection( + (this.sortOrder == SortOrder.ASCENDING) ? SWT.UP : SWT.DOWN); + } + }); + } + + if (column.widthPercent > 0) { + this.columnsWithSameWidth = false; + } + } + } + + private void updateTableRows( + final int pageNumber, + final int pageSize, + final String sortColumn, + final SortOrder sortOrder) { + + // first remove all rows if there are some + this.table.removeAll(); + + // get page data and create rows + this.restCall.newBuilder() + .withPaging(pageNumber, pageSize) + .withSorting(sortColumn, sortOrder) + .withFilterAttributes(this.filter) + .call() + .map(this::createTableRowsFromPage) + .map(this.navigator::update) + .onErrorDo(t -> { + // TODO error handling + }); + + this.layout(); + } + + private Page createTableRowsFromPage(final Page page) { + for (final ROW row : page.content) { + 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 column : this.columns) { + final Object value = column.valueSupplier.apply(row); + if (value instanceof Boolean) { + // TODO set an image or HTML with checkbox + item.setText(index, String.valueOf(value)); + } else { + item.setText(index, String.valueOf(value)); + } + index++; + } + if (this.actions != null) { + // TODO + } + } + + return page; + } + + private void adaptColumnWidth(final Event event) { + try { + final int currentTableWidth = this.table.getParent().getClientArea().width; + + int index = 0; + for (final ColumnDefinition column : this.columns) { + + final int percentage = (this.columnsWithSameWidth) + ? 100 / this.columns.size() + : column.widthPercent; + + final TableColumn tableColumn = this.table.getColumn(index); + tableColumn.setWidth(currentTableWidth / 100 * percentage); + + index++; + } + + } catch (final Exception e) { + log.warn("Failed to adaptColumnWidth: ", e); + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableBuilder.java new file mode 100644 index 00000000..637c7540 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableBuilder.java @@ -0,0 +1,92 @@ +/* + * 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.table; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.widgets.Composite; + +import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gbl.model.Page; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; +import ch.ethz.seb.sebserver.gui.service.widget.WidgetFactory; + +/** + * new TableBuilder(RestCall) + * .withPaging(pageSize) + * .withColumn(new ColumnDefinition( + * columnName:String, + * displayName:LocTextKey, + * tooltip:LocTextKey, + * width:int, + * valueSupplier:Function, + * sortable:boolean, + * columnFilter:TableColumnFilter)) + * .withAction(action:TableRowAction) + * .withSelectableRows(boolean) + * .compose(parent:Composit, group:Composite); + * */ +public class TableBuilder { + + private final WidgetFactory widgetFactory; + final RestCall> restCall; + final List> columns = new ArrayList<>(); + final List actions = new ArrayList<>(); + + private int pageSize = -1; + private boolean selectableRows = false; + + public TableBuilder( + final WidgetFactory widgetFactory, + final RestCall> restCall) { + + this.widgetFactory = widgetFactory; + this.restCall = restCall; + } + + public TableBuilder withPaging(final int pageSize) { + this.pageSize = pageSize; + return this; + } + + public TableBuilder withColumn(final ColumnDefinition columnDef) { + this.columns.add(columnDef); + return this; + } + + public TableBuilder withSelectableRows() { + this.selectableRows = true; + return this; + } + + public TableBuilder withAction(final TableRowAction action) { + this.actions.add(action); + return this; + } + + public EntityTable compose(final Composite parent) { + final boolean withFilter = this.columns + .stream() + .filter(c -> c.filter != null) + .findFirst() + .isPresent(); + + return new EntityTable<>( + parent, + this.restCall, + this.widgetFactory, + this.columns, + this.actions, + this.pageSize, + withFilter, + this.selectableRows); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableFilter.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableFilter.java new file mode 100644 index 00000000..22ecd9ae --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableFilter.java @@ -0,0 +1,31 @@ +/* + * 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.table; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.springframework.util.MultiValueMap; + +import ch.ethz.seb.sebserver.gbl.model.Entity; +import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.FilterAttributeSupplier; + +public class TableFilter extends Composite implements FilterAttributeSupplier { + + private static final long serialVersionUID = -2460403977147440766L; + + TableFilter(final EntityTable parent) { + super(parent, SWT.NONE); + } + + @Override + public MultiValueMap getAttributes() { + // TODO Auto-generated method stub + return null; + } +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableNavigator.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableNavigator.java new file mode 100644 index 00000000..72dbcc2a --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableNavigator.java @@ -0,0 +1,112 @@ +/* + * 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.table; + +import org.eclipse.rap.rwt.RWT; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.layout.RowLayout; +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; + +public class TableNavigator extends Composite { + + private static final long serialVersionUID = -7349918232061226192L; + + private final int pageNavSize = 3; + private final EntityTable entityTable; + + TableNavigator(final EntityTable entityTable) { + super(entityTable, SWT.NONE); + super.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + + final GridLayout layout = new GridLayout(3, true); + layout.marginLeft = 20; + super.setLayout(layout); + + this.entityTable = entityTable; + } + + public Page update(final Page pageData) { + // clear all + RWTUtils.clearComposite(this); + + final int pageNumber = pageData.getPageNumber(); + final int numberOfPages = pageData.getNumberOfPages(); + + createPagingHeader(pageNumber, numberOfPages); + + final Composite numNav = new Composite(this, SWT.NONE); + numNav.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + final RowLayout rowLayout = new RowLayout(SWT.HORIZONTAL); + rowLayout.spacing = 5; + numNav.setLayout(rowLayout); + + if (numberOfPages > 1) { + if (pageNumber > 1) { + createRewardLabel(pageNumber, numNav); + } + + for (int i = pageNumber - this.pageNavSize; i < pageNumber + this.pageNavSize; i++) { + if (i >= 1 && i <= numberOfPages) { + createPageNumberLabel(i, i != pageNumber, numNav); + } + } + + if (pageNumber < numberOfPages) { + createForwardLabel(pageNumber, numNav); + } + } + + this.layout(); + + return pageData; + } + + private void createPagingHeader(final int page, final int of) { + final Label pageHeader = new Label(this, SWT.NONE); + pageHeader.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); + pageHeader.setText("Page " + page + "/" + of); + } + + private void createPageNumberLabel(final int page, final boolean selectable, final Composite parent) { + final Label pageLabel = new Label(parent, SWT.NONE); + + pageLabel.setText(" " + String.valueOf(page) + " "); + if (selectable) { + pageLabel.setData(RWT.CUSTOM_VARIANT, "action"); + pageLabel.addListener(SWT.MouseDown, event -> { + this.entityTable.selectPage(page); + }); + } + } + + private void createForwardLabel(final int pageNumber, final Composite parent) { + final Label forward = new Label(parent, SWT.NONE); + forward.setText(">"); + forward.setData(RWT.CUSTOM_VARIANT, "action"); + forward.addListener(SWT.MouseDown, event -> { + this.entityTable.selectPage(pageNumber + 1); + }); + } + + private void createRewardLabel(final int pageNumber, final Composite parent) { + final Label reward = new Label(parent, SWT.NONE); + reward.setText("<"); + reward.setData(RWT.CUSTOM_VARIANT, "action"); + reward.addListener(SWT.MouseDown, event -> { + this.entityTable.selectPage(pageNumber - 1); + }); + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableRowAction.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableRowAction.java new file mode 100644 index 00000000..d1c669cc --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/table/TableRowAction.java @@ -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.table; + +public class TableRowAction { + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java index 3c09184a..f9de2839 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/widget/WidgetFactory.java @@ -8,8 +8,7 @@ package ch.ethz.seb.sebserver.gui.service.widget; -import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_TREE_ITEM_TEXT_DATA_KEY; -import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.POLYGLOT_WIDGET_FUNCTION_KEY; +import static ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService.*; import java.io.InputStream; import java.util.Iterator; @@ -39,12 +38,17 @@ import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +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; 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.table.TableBuilder; @Lazy @Service @@ -158,6 +162,12 @@ public class WidgetFactory { return label; } + public Label labelLocalizedTitle(final Composite content, final LocTextKey locTextKey) { + final Label labelLocalized = labelLocalized(content, RWTUtils.TEXT_NAME_H2, 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); this.injectI18n(tree); @@ -188,15 +198,23 @@ public class WidgetFactory { return item; } + public TableBuilder entityTableBuilder(final RestCall> apiCall) { + return new TableBuilder<>(this, apiCall); + } + public Table tableLocalized(final Composite parent) { - final Table table = new Table(parent, SWT.NONE); + final Table table = new Table(parent, SWT.SINGLE | SWT.NO_SCROLL); this.injectI18n(table); return table; } - public TableColumn tableColumnLocalized(final Table table, final String locTextKey) { + public TableColumn tableColumnLocalized( + final Table table, + final LocTextKey locTextKey, + final LocTextKey toolTipKey) { + final TableColumn tableColumn = new TableColumn(table, SWT.NONE); - this.injectI18n(tableColumn, new LocTextKey(locTextKey)); + this.injectI18n(tableColumn, locTextKey, toolTipKey); return tableColumn; } @@ -322,9 +340,14 @@ public class WidgetFactory { table.setData(POLYGLOT_WIDGET_FUNCTION_KEY, tableFunction(this.i18nSupport)); } - public void injectI18n(final TableColumn tableColumn, final LocTextKey locTextKey) { + public void injectI18n(final TableColumn tableColumn, final LocTextKey locTextKey, final LocTextKey locTooltipKey) { tableColumn.setData(POLYGLOT_TREE_ITEM_TEXT_DATA_KEY, locTextKey); tableColumn.setText(this.i18nSupport.getText(locTextKey)); + + if (locTooltipKey != null) { + tableColumn.setData(POLYGLOT_TREE_ITEM_TOOLTIP_DATA_KEY, locTooltipKey); + tableColumn.setToolTipText(this.i18nSupport.getText(locTooltipKey)); + } } public void injectI18n(final TableItem tableItem, final LocTextKey... locTextKey) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/PaginationService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/PaginationService.java index c5c6971f..72d8a8e2 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/PaginationService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/PaginationService.java @@ -27,6 +27,7 @@ import ch.ethz.seb.sebserver.gbl.model.Page; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.util.Result; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.ExamRecordDynamicSqlSupport; +import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.InstitutionRecordDynamicSqlSupport; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserActivityLogRecordDynamicSqlSupport; import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport; @@ -36,29 +37,26 @@ import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamic public class PaginationService { public enum SortOrder { - ASCENDING("+"), - DESCENDING("-"); + ASCENDING, + DESCENDING; - public final String prefix; + public final static String DESCENDING_PREFIX = "-"; - private SortOrder(final String prefix) { - this.prefix = prefix; + public String encode(final String sort) { + return (this == DESCENDING) ? DESCENDING_PREFIX + sort : sort; } - public static SortOrder getSortOrder(final String sort) { - return (sort != null && sort.startsWith(DESCENDING.prefix)) + public static String decode(final String sort) { + return (sort != null && sort.startsWith(DESCENDING_PREFIX)) + ? sort.substring(1) + : sort; + } + + public static SortOrder getSortOrder(final String encoded) { + return (encoded != null && encoded.startsWith(DESCENDING_PREFIX)) ? SortOrder.DESCENDING : SortOrder.ASCENDING; } - - public static String getSortColumn(final String sort) { - return (sort == null) - ? null - : (sort.startsWith(SortOrder.ASCENDING.prefix) || sort.startsWith(SortOrder.DESCENDING.prefix)) - ? sort.substring(1) - : sort; - } - } private final int defaultPageSize; @@ -137,10 +135,11 @@ public class PaginationService { final com.github.pagehelper.Page startPage = PageHelper.startPage(getPageNumber(pageNumber), getPageSize(pageSize), true, true, false); - if (table != null) { + if (table != null && StringUtils.isNoneBlank(sort)) { + final SortOrder sortOrder = SortOrder.getSortOrder(sort); final String sortColumnName = verifySortColumnName(sort, table); if (StringUtils.isNoneBlank(sortColumnName)) { - switch (SortOrder.getSortOrder(sort)) { + switch (sortOrder) { case DESCENDING: { PageHelper.orderBy(sortColumnName + " DESC"); break; @@ -178,7 +177,7 @@ public class PaginationService { final Map mapping = this.sortColumnMapping.get(table.name()); if (mapping != null) { - final String sortColumn = SortOrder.getSortColumn(sort); + final String sortColumn = SortOrder.decode(sort); if (StringUtils.isBlank(sortColumn)) { return this.defaultSortColumn.get(table.name()); } @@ -191,6 +190,24 @@ public class PaginationService { // TODO is it possible to generate this within MyBatis generator? private void initSortColumnMapping() { + // Institution Table + final Map institutionTableMap = new HashMap<>(); + institutionTableMap.put( + Domain.INSTITUTION.ATTR_NAME, + InstitutionRecordDynamicSqlSupport.name.name()); + institutionTableMap.put( + Domain.INSTITUTION.ATTR_URL_SUFFIX, + InstitutionRecordDynamicSqlSupport.urlSuffix.name()); + institutionTableMap.put( + Domain.INSTITUTION.ATTR_ACTIVE, + InstitutionRecordDynamicSqlSupport.active.name()); + this.sortColumnMapping.put( + InstitutionRecordDynamicSqlSupport.institutionRecord.name(), + institutionTableMap); + this.defaultSortColumn.put( + InstitutionRecordDynamicSqlSupport.institutionRecord.name(), + Domain.INSTITUTION.ATTR_ID); + // User Table final Map userTableMap = new HashMap<>(); userTableMap.put(Domain.USER.ATTR_NAME, UserRecordDynamicSqlSupport.name.name()); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/MockupLmsAPITemplate.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/MockupLmsAPITemplate.java index cfd7df25..4bfdfc89 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/MockupLmsAPITemplate.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/lms/impl/MockupLmsAPITemplate.java @@ -107,7 +107,7 @@ final class MockupLmsAPITemplate implements LmsAPITemplate { ? -1 : 1; - final String _sort = SortOrder.getSortColumn(sort); + final String _sort = SortOrder.decode(sort); final Comparator comp = (_sort != null) ? (_sort.equals(QuizData.FILTER_ATTR_START_TIME)) ? (q1, q2) -> q1.startTime.compareTo(q2.startTime) * orderFactor diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java index 4540e236..58fe545c 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAdministrationController.java @@ -30,9 +30,9 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; import ch.ethz.seb.sebserver.gbl.api.POSTMapper; import ch.ethz.seb.sebserver.gbl.api.SEBServerRestEndpoints; +import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP; import ch.ethz.seb.sebserver.gbl.model.Entity; import ch.ethz.seb.sebserver.gbl.model.EntityKey; import ch.ethz.seb.sebserver.gbl.model.EntityType; @@ -137,7 +137,7 @@ public class ExamAdministrationController extends ActivatableEntityController exam1.name.compareTo(exam2.name)); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/oauth/RevokeTokenEndpoint.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/oauth/RevokeTokenEndpoint.java index d082001d..bb855b84 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/oauth/RevokeTokenEndpoint.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/oauth/RevokeTokenEndpoint.java @@ -12,9 +12,7 @@ import java.util.Collection; import javax.servlet.http.HttpServletRequest; -import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.context.ApplicationEvent; -import org.springframework.context.annotation.Import; import org.springframework.context.event.EventListener; import org.springframework.http.HttpStatus; import org.springframework.security.oauth2.common.OAuth2AccessToken; @@ -29,7 +27,6 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; @Controller @WebServiceProfile -@Import(DataSourceAutoConfiguration.class) public class RevokeTokenEndpoint { private final ConsumerTokenServices tokenServices; diff --git a/src/main/resources/config/application-demo.properties b/src/main/resources/config/application-demo.properties index d648188c..18c241ad 100644 --- a/src/main/resources/config/application-demo.properties +++ b/src/main/resources/config/application-demo.properties @@ -18,8 +18,6 @@ sebserver.webservice.api.exam.accessTokenValiditySeconds=1800 sebserver.webservice.api.exam.refreshTokenValiditySeconds=-1 sebserver.webservice.api.redirect.unauthorized=http://=0.0.0.0:8080/gui -sebserver.webservice.api.redirect.unauthorized=none - server.servlet.session.cookie.http-only=true server.servlet.session.tracking-modes=cookie diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 46d03ed6..e3a0e38c 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -29,3 +29,13 @@ sebserver.actionpane.title=Actions sebserver.activities.inst=Institution sebserver.error.unexpected=Unexpected Error + + +################################ +# Institution +################################ + +sebserver.institution.list.title=Institutions +sebserver.institution.list.column.name=Name +sebserver.institution.list.column.urlSuffix=URL Suffix +sebserver.institution.list.column.active=Active \ No newline at end of file diff --git a/src/main/resources/static/css/sebserver.css b/src/main/resources/static/css/sebserver.css index 94efc8b8..91f13de7 100644 --- a/src/main/resources/static/css/sebserver.css +++ b/src/main/resources/static/css/sebserver.css @@ -26,6 +26,21 @@ Label { text-shadow: none; } +Label.action { + font: 12px Verdana, "Lucida Sans", Arial, Helvetica, sans-serif; + color: #82BE1E; + background-color: transparent; + background-image: none; + background-repeat: repeat; + background-position: left top; + border: none; + border-radius: 0; + text-decoration: none; + cursor: default; + opacity: 1; + text-shadow: none; +} + Label.h1 { font: 25px Arial, Helvetica, sans-serif; height: 28px;