added SEBSever logo
added Institution show case added table attribute to user session
This commit is contained in:
		
							parent
							
								
									b27c79e1d8
								
							
						
					
					
						commit
						9f752bf145
					
				
					 23 changed files with 386 additions and 48 deletions
				
			
		|  | @ -19,6 +19,7 @@ public interface Entity extends ModelIdAware { | ||||||
|     public static final String FILTER_ATTR_INSTITUTION = API.PARAM_INSTITUTION_ID; |     public static final String FILTER_ATTR_INSTITUTION = API.PARAM_INSTITUTION_ID; | ||||||
|     public static final String FILTER_ATTR_ACTIVE = "active"; |     public static final String FILTER_ATTR_ACTIVE = "active"; | ||||||
|     public static final String FILTER_ATTR_NAME = "name"; |     public static final String FILTER_ATTR_NAME = "name"; | ||||||
|  |     public static final String FILTER_ATTR_URL_SUFFIX = "urlsuffix"; | ||||||
| 
 | 
 | ||||||
|     /** Get the type of the entity. |     /** Get the type of the entity. | ||||||
|      * |      * | ||||||
|  |  | ||||||
|  | @ -185,7 +185,9 @@ public class ConfigTemplateForm implements TemplateComposer { | ||||||
|                     () -> this.resourceService.getAttributeTypeResources()); |                     () -> this.resourceService.getAttributeTypeResources()); | ||||||
| 
 | 
 | ||||||
|             final EntityTable<TemplateAttribute> attrTable = |             final EntityTable<TemplateAttribute> attrTable = | ||||||
|                     this.pageService.entityTableBuilder(this.restService.getRestCall(GetTemplateAttributePage.class)) |                     this.pageService.entityTableBuilder( | ||||||
|  |                             Domain.CONFIGURATION_NODE.TYPE_NAME + "_Template", | ||||||
|  |                             this.restService.getRestCall(GetTemplateAttributePage.class)) | ||||||
|                             .withRestCallAdapter(restCall -> restCall.withURIVariable( |                             .withRestCallAdapter(restCall -> restCall.withURIVariable( | ||||||
|                                     API.PARAM_PARENT_MODEL_ID, |                                     API.PARAM_PARENT_MODEL_ID, | ||||||
|                                     entityKey.modelId)) |                                     entityKey.modelId)) | ||||||
|  | @ -226,7 +228,7 @@ public class ConfigTemplateForm implements TemplateComposer { | ||||||
|                     .withParentEntityKey(entityKey) |                     .withParentEntityKey(entityKey) | ||||||
|                     .withSelect( |                     .withSelect( | ||||||
|                             attrTable::getSelection, |                             attrTable::getSelection, | ||||||
|                             PageAction::applySingleSelection, |                             PageAction::applySingleSelectionAsEntityKey, | ||||||
|                             EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) |                             EMPTY_ATTRIBUTE_SELECTION_TEXT_KEY) | ||||||
|                     .publishIf(() -> attrTable.hasAnyContent()) |                     .publishIf(() -> attrTable.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -519,7 +519,7 @@ public class ExamForm implements TemplateComposer { | ||||||
|                     .withParentEntityKey(entityKey) |                     .withParentEntityKey(entityKey) | ||||||
|                     .withSelect( |                     .withSelect( | ||||||
|                             indicatorTable::getSelection, |                             indicatorTable::getSelection, | ||||||
|                             PageAction::applySingleSelection, |                             PageAction::applySingleSelectionAsEntityKey, | ||||||
|                             INDICATOR_EMPTY_SELECTION_TEXT_KEY) |                             INDICATOR_EMPTY_SELECTION_TEXT_KEY) | ||||||
|                     .publishIf(() -> modifyGrant && indicatorTable.hasAnyContent() && editable) |                     .publishIf(() -> modifyGrant && indicatorTable.hasAnyContent() && editable) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -207,7 +207,7 @@ public class ExamList implements TemplateComposer { | ||||||
|                 .publishIf(userGrant::im) |                 .publishIf(userGrant::im) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST) |                 .newAction(ActionDefinition.EXAM_VIEW_FROM_LIST) | ||||||
|                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                 .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(table::hasAnyContent) |                 .publishIf(table::hasAnyContent) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST) |                 .newAction(ActionDefinition.EXAM_MODIFY_FROM_LIST) | ||||||
|  |  | ||||||
|  | @ -13,8 +13,10 @@ import org.springframework.beans.factory.annotation.Value; | ||||||
| import org.springframework.context.annotation.Lazy; | import org.springframework.context.annotation.Lazy; | ||||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||||
| 
 | 
 | ||||||
|  | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
| import ch.ethz.seb.sebserver.gbl.api.EntityType; | import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Domain; | import ch.ethz.seb.sebserver.gbl.model.Domain; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.model.Entity; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.institution.Institution; | import ch.ethz.seb.sebserver.gbl.model.institution.Institution; | ||||||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||||
| import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; | import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; | ||||||
|  | @ -29,7 +31,9 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.institution.GetIn | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser.GrantCheck; | ||||||
| import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; | import ch.ethz.seb.sebserver.gui.table.ColumnDefinition; | ||||||
|  | import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; | ||||||
| import ch.ethz.seb.sebserver.gui.table.EntityTable; | import ch.ethz.seb.sebserver.gui.table.EntityTable; | ||||||
|  | import ch.ethz.seb.sebserver.gui.table.TableFilter.CriteriaType; | ||||||
| 
 | 
 | ||||||
| @Lazy | @Lazy | ||||||
| @Component | @Component | ||||||
|  | @ -49,6 +53,12 @@ public class InstitutionList implements TemplateComposer { | ||||||
|     private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = |     private static final LocTextKey EMPTY_SELECTION_TEXT_KEY = | ||||||
|             new LocTextKey("sebserver.institution.info.pleaseSelect"); |             new LocTextKey("sebserver.institution.info.pleaseSelect"); | ||||||
| 
 | 
 | ||||||
|  |     private final TableFilterAttribute nameFilter = | ||||||
|  |             new TableFilterAttribute(CriteriaType.TEXT, Entity.FILTER_ATTR_NAME); | ||||||
|  |     private final TableFilterAttribute urlSuffixFilter = | ||||||
|  |             new TableFilterAttribute(CriteriaType.TEXT, Institution.FILTER_ATTR_URL_SUFFIX); | ||||||
|  |     private final TableFilterAttribute activityFilter; | ||||||
|  | 
 | ||||||
|     private final PageService pageService; |     private final PageService pageService; | ||||||
|     private final RestService restService; |     private final RestService restService; | ||||||
|     private final CurrentUser currentUser; |     private final CurrentUser currentUser; | ||||||
|  | @ -64,6 +74,12 @@ public class InstitutionList implements TemplateComposer { | ||||||
|         this.restService = restService; |         this.restService = restService; | ||||||
|         this.currentUser = currentUser; |         this.currentUser = currentUser; | ||||||
|         this.pageSize = pageSize; |         this.pageSize = pageSize; | ||||||
|  | 
 | ||||||
|  |         this.activityFilter = new TableFilterAttribute( | ||||||
|  |                 CriteriaType.SINGLE_SELECTION, | ||||||
|  |                 Institution.FILTER_ATTR_ACTIVE, | ||||||
|  |                 Constants.TRUE_STRING, | ||||||
|  |                 this.pageService.getResourceService()::activityResources); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  | @ -84,19 +100,22 @@ public class InstitutionList implements TemplateComposer { | ||||||
|                                 Domain.INSTITUTION.ATTR_NAME, |                                 Domain.INSTITUTION.ATTR_NAME, | ||||||
|                                 NAME_TEXT_KEY, |                                 NAME_TEXT_KEY, | ||||||
|                                 Institution::getName) |                                 Institution::getName) | ||||||
|                                         .sortable()) |                                         .sortable() | ||||||
|  |                                         .withFilter(this.nameFilter)) | ||||||
|                         .withColumn(new ColumnDefinition<>( |                         .withColumn(new ColumnDefinition<>( | ||||||
|                                 Domain.INSTITUTION.ATTR_URL_SUFFIX, |                                 Domain.INSTITUTION.ATTR_URL_SUFFIX, | ||||||
|                                 URL_TEXT_KEY, |                                 URL_TEXT_KEY, | ||||||
|                                 Institution::getUrlSuffix) |                                 Institution::getUrlSuffix) | ||||||
|                                         .sortable()) |                                         .sortable() | ||||||
|  |                                         .withFilter(this.urlSuffixFilter)) | ||||||
|                         .withColumn(new ColumnDefinition<Institution>( |                         .withColumn(new ColumnDefinition<Institution>( | ||||||
|                                 Domain.INSTITUTION.ATTR_ACTIVE, |                                 Domain.INSTITUTION.ATTR_ACTIVE, | ||||||
|                                 ACTIVE_TEXT_KEY, |                                 ACTIVE_TEXT_KEY, | ||||||
|                                 entity -> this.pageService |                                 entity -> this.pageService | ||||||
|                                         .getResourceService() |                                         .getResourceService() | ||||||
|                                         .localizedActivityResource().apply(entity.active)) |                                         .localizedActivityResource().apply(entity.active)) | ||||||
|                                                 .sortable()) |                                                 .sortable() | ||||||
|  |                                                 .withFilter(this.activityFilter)) | ||||||
|                         .withDefaultAction(pageActionBuilder |                         .withDefaultAction(pageActionBuilder | ||||||
|                                 .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) |                                 .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) | ||||||
|                                 .create()) |                                 .create()) | ||||||
|  | @ -111,21 +130,31 @@ public class InstitutionList implements TemplateComposer { | ||||||
|                 .newAction(ActionDefinition.INSTITUTION_NEW) |                 .newAction(ActionDefinition.INSTITUTION_NEW) | ||||||
|                 .publishIf(instGrant::w) |                 .publishIf(instGrant::w) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.USER_ACCOUNT_NEW) |  | ||||||
|                 .publishIf(userGrant::w) |  | ||||||
| 
 |  | ||||||
|                 .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) |                 .newAction(ActionDefinition.INSTITUTION_VIEW_FROM_LIST) | ||||||
|                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                 .withSelect( | ||||||
|  |                         table::getSelection, | ||||||
|  |                         PageAction::applySingleSelectionAsEntityKey, | ||||||
|  |                         EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> table.hasAnyContent()) |                 .publishIf(() -> table.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST) |                 .newAction(ActionDefinition.INSTITUTION_MODIFY_FROM_LIST) | ||||||
|                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                 .withSelect( | ||||||
|  |                         table::getSelection, | ||||||
|  |                         PageAction::applySingleSelectionAsEntityKey, | ||||||
|  |                         EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> instGrant.m() && table.hasAnyContent()) |                 .publishIf(() -> instGrant.m() && table.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY) |                 .newAction(ActionDefinition.INSTITUTION_TOGGLE_ACTIVITY) | ||||||
|                 .withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY)) |                 .withExec(this.pageService.activationToggleActionFunction(table, EMPTY_SELECTION_TEXT_KEY)) | ||||||
|                 .withConfirm(this.pageService.confirmDeactivation(table)) |                 .withConfirm(this.pageService.confirmDeactivation(table)) | ||||||
|                 .publishIf(() -> instGrant.m() && table.hasAnyContent()); |                 .publishIf(() -> instGrant.m() && table.hasAnyContent()) | ||||||
|  | 
 | ||||||
|  |                 .newAction(ActionDefinition.INSTITUTION_USER_ACCOUNT_NEW) | ||||||
|  |                 .withSelect( | ||||||
|  |                         table::getSelection, | ||||||
|  |                         PageAction::applySingleSelectionAsParentEntityKey, | ||||||
|  |                         EMPTY_SELECTION_TEXT_KEY) | ||||||
|  |                 .publishIf(() -> table.hasAnyContent() && userGrant.w()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -157,13 +157,13 @@ public class LmsSetupList implements TemplateComposer { | ||||||
|                 .publishIf(userGrant::iw) |                 .publishIf(userGrant::iw) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST) |                 .newAction(ActionDefinition.LMS_SETUP_VIEW_FROM_LIST) | ||||||
|                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                 .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> table.hasAnyContent()) |                 .publishIf(() -> table.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST) |                 .newAction(ActionDefinition.LMS_SETUP_MODIFY_FROM_LIST) | ||||||
|                 .withSelect( |                 .withSelect( | ||||||
|                         table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), |                         table.getGrantedSelection(currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), | ||||||
|                         PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                         PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> userGrant.im() && table.hasAnyContent()); |                 .publishIf(() -> userGrant.im() && table.hasAnyContent()); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -136,7 +136,7 @@ public class MonitoringRunningExamList implements TemplateComposer { | ||||||
|         actionBuilder |         actionBuilder | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.MONITOR_EXAM_FROM_LIST) |                 .newAction(ActionDefinition.MONITOR_EXAM_FROM_LIST) | ||||||
|                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                 .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER)); |                 .publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER)); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -161,13 +161,13 @@ public class SebClientConfigList implements TemplateComposer { | ||||||
|                 .publishIf(clientConfigGrant::iw) |                 .publishIf(clientConfigGrant::iw) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST) |                 .newAction(ActionDefinition.SEB_CLIENT_CONFIG_VIEW_FROM_LIST) | ||||||
|                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                 .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> table.hasAnyContent()) |                 .publishIf(() -> table.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST) |                 .newAction(ActionDefinition.SEB_CLIENT_CONFIG_MODIFY_FROM_LIST) | ||||||
|                 .withSelect( |                 .withSelect( | ||||||
|                         table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), |                         table.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), | ||||||
|                         PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                         PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> clientConfigGrant.im() && table.hasAnyContent()); |                 .publishIf(() -> clientConfigGrant.im() && table.hasAnyContent()); | ||||||
| 
 | 
 | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -192,19 +192,19 @@ public class SebExamConfigList implements TemplateComposer { | ||||||
|                 .publishIf(examConfigGrant::iw) |                 .publishIf(examConfigGrant::iw) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) |                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_VIEW_PROP_FROM_LIST) | ||||||
|                 .withSelect(configTable::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                 .withSelect(configTable::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> configTable.hasAnyContent()) |                 .publishIf(() -> configTable.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) |                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_PROP_FROM_LIST) | ||||||
|                 .withSelect( |                 .withSelect( | ||||||
|                         configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), |                         configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), | ||||||
|                         PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                         PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) |                 .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST) |                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_MODIFY_FROM_LIST) | ||||||
|                 .withSelect( |                 .withSelect( | ||||||
|                         configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), |                         configTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), | ||||||
|                         PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                         PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) |                 .publishIf(() -> examConfigGrant.im() && configTable.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) |                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_IMPORT_TO_NEW_CONFIG) | ||||||
|  | @ -217,14 +217,14 @@ public class SebExamConfigList implements TemplateComposer { | ||||||
|                 .publishIf(examConfigGrant::iw) |                 .publishIf(examConfigGrant::iw) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) |                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_VIEW_FROM_LIST) | ||||||
|                 .withSelect(templateTable::getSelection, PageAction::applySingleSelection, |                 .withSelect(templateTable::getSelection, PageAction::applySingleSelectionAsEntityKey, | ||||||
|                         EMPTY_TEMPLATE_SELECTION_TEXT_KEY) |                         EMPTY_TEMPLATE_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> templateTable.hasAnyContent()) |                 .publishIf(() -> templateTable.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST) |                 .newAction(ActionDefinition.SEB_EXAM_CONFIG_TEMPLATE_MODIFY_FROM_LIST) | ||||||
|                 .withSelect( |                 .withSelect( | ||||||
|                         templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), |                         templateTable.getGrantedSelection(this.currentUser, NO_MODIFY_PRIVILEGE_ON_OTHER_INSTITUION), | ||||||
|                         PageAction::applySingleSelection, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) |                         PageAction::applySingleSelectionAsEntityKey, EMPTY_TEMPLATE_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent()); |                 .publishIf(() -> examConfigGrant.im() && templateTable.hasAnyContent()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -342,7 +342,7 @@ public class SebExamConfigPropForm implements TemplateComposer { | ||||||
|                     final ExamConfigurationMap selectedROWData = getSelectedExamMapping(table); |                     final ExamConfigurationMap selectedROWData = getSelectedExamMapping(table); | ||||||
|                     return new HashSet<>(Arrays.asList(new EntityKey(selectedROWData.examId, EntityType.EXAM))); |                     return new HashSet<>(Arrays.asList(new EntityKey(selectedROWData.examId, EntityType.EXAM))); | ||||||
|                 }) |                 }) | ||||||
|                 .withExec(PageAction::applySingleSelection) |                 .withExec(PageAction::applySingleSelectionAsEntityKey) | ||||||
|                 .create(); |                 .create(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -195,7 +195,7 @@ public class UserAccountList implements TemplateComposer { | ||||||
|                 .publishIf(userGrant::iw) |                 .publishIf(userGrant::iw) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST) |                 .newAction(ActionDefinition.USER_ACCOUNT_VIEW_FROM_LIST) | ||||||
|                 .withSelect(table::getSelection, PageAction::applySingleSelection, EMPTY_SELECTION_TEXT_KEY) |                 .withSelect(table::getSelection, PageAction::applySingleSelectionAsEntityKey, EMPTY_SELECTION_TEXT_KEY) | ||||||
|                 .publishIf(() -> table.hasAnyContent()) |                 .publishIf(() -> table.hasAnyContent()) | ||||||
| 
 | 
 | ||||||
|                 .newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST) |                 .newAction(ActionDefinition.USER_ACCOUNT_MODIFY_FROM_LIST) | ||||||
|  | @ -214,7 +214,7 @@ public class UserAccountList implements TemplateComposer { | ||||||
|             throw new PageMessageException(NO_EDIT_RIGHT_MESSAGE); |             throw new PageMessageException(NO_EDIT_RIGHT_MESSAGE); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return PageAction.applySingleSelection(pageAction); |         return PageAction.applySingleSelectionAsEntityKey(pageAction); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private String getLocaleDisplayText(final UserInfo userInfo) { |     private String getLocaleDisplayText(final UserInfo userInfo) { | ||||||
|  |  | ||||||
|  | @ -25,7 +25,8 @@ public enum ActionDefinition { | ||||||
|     INSTITUTION_NEW( |     INSTITUTION_NEW( | ||||||
|             new LocTextKey("sebserver.institution.action.new"), |             new LocTextKey("sebserver.institution.action.new"), | ||||||
|             ImageIcon.INSTITUTION, |             ImageIcon.INSTITUTION, | ||||||
|             PageStateDefinitionImpl.INSTITUTION_EDIT), |             PageStateDefinitionImpl.INSTITUTION_EDIT, | ||||||
|  |             ActionCategory.FORM), | ||||||
|     INSTITUTION_VIEW_FROM_LIST( |     INSTITUTION_VIEW_FROM_LIST( | ||||||
|             new LocTextKey("sebserver.institution.action.list.view"), |             new LocTextKey("sebserver.institution.action.list.view"), | ||||||
|             ImageIcon.SHOW, |             ImageIcon.SHOW, | ||||||
|  | @ -71,6 +72,11 @@ public enum ActionDefinition { | ||||||
|             ImageIcon.TOGGLE_ON, |             ImageIcon.TOGGLE_ON, | ||||||
|             PageStateDefinitionImpl.INSTITUTION_VIEW, |             PageStateDefinitionImpl.INSTITUTION_VIEW, | ||||||
|             ActionCategory.FORM), |             ActionCategory.FORM), | ||||||
|  |     INSTITUTION_USER_ACCOUNT_NEW( | ||||||
|  |             new LocTextKey("sebserver.useraccount.action.new"), | ||||||
|  |             ImageIcon.USER, | ||||||
|  |             PageStateDefinitionImpl.USER_ACCOUNT_EDIT, | ||||||
|  |             ActionCategory.INSTITUTION_LIST), | ||||||
| 
 | 
 | ||||||
|     USER_ACCOUNT_VIEW_LIST( |     USER_ACCOUNT_VIEW_LIST( | ||||||
|             new LocTextKey("sebserver.useraccount.action.list"), |             new LocTextKey("sebserver.useraccount.action.list"), | ||||||
|  |  | ||||||
|  | @ -147,8 +147,9 @@ public class ResourceService { | ||||||
| 
 | 
 | ||||||
|     public List<Tuple<String>> activityResources() { |     public List<Tuple<String>> activityResources() { | ||||||
|         final List<Tuple<String>> result = new ArrayList<>(); |         final List<Tuple<String>> result = new ArrayList<>(); | ||||||
|         result.add(new Tuple<>("true", this.i18nSupport.getText("sebserver.overall.status.active"))); |         result.add(new Tuple<>(Constants.TRUE_STRING, this.i18nSupport.getText("sebserver.overall.status.active"))); | ||||||
|         result.add(new Tuple<>("false", this.i18nSupport.getText("sebserver.overall.status.inactive"))); |         result.add(new Tuple<>(Constants.FALSE_STRING, this.i18nSupport.getText("sebserver.overall.status.inactive"))); | ||||||
|  |         result.add(new Tuple<>(StringUtils.EMPTY, StringUtils.EMPTY)); | ||||||
|         return result; |         return result; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -47,6 +47,7 @@ import ch.ethz.seb.sebserver.gui.service.page.impl.PageState; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | ||||||
| import ch.ethz.seb.sebserver.gui.table.EntityTable; | import ch.ethz.seb.sebserver.gui.table.EntityTable; | ||||||
| import ch.ethz.seb.sebserver.gui.table.TableBuilder; | import ch.ethz.seb.sebserver.gui.table.TableBuilder; | ||||||
| import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | ||||||
|  | @ -92,6 +93,11 @@ public interface PageService { | ||||||
|      * @return the RestService bean */ |      * @return the RestService bean */ | ||||||
|     RestService getRestService(); |     RestService getRestService(); | ||||||
| 
 | 
 | ||||||
|  |     /** Use this to get the CurrentUser facade | ||||||
|  |      * | ||||||
|  |      * @return the CurrentUser facade */ | ||||||
|  |     CurrentUser getCurrentUser(); | ||||||
|  | 
 | ||||||
|     /** Get the PageState of the current user. |     /** Get the PageState of the current user. | ||||||
|      * |      * | ||||||
|      * @return PageState of the current user. */ |      * @return PageState of the current user. */ | ||||||
|  | @ -187,7 +193,19 @@ public interface PageService { | ||||||
|      * @param apiCall the SEB Server API RestCall that feeds the table with data |      * @param apiCall the SEB Server API RestCall that feeds the table with data | ||||||
|      * @param <T> the type of the Entity of the table |      * @param <T> the type of the Entity of the table | ||||||
|      * @return TableBuilder of specified type */ |      * @return TableBuilder of specified type */ | ||||||
|     <T extends Entity> TableBuilder<T> entityTableBuilder(RestCall<Page<T>> apiCall); |     default <T extends Entity> TableBuilder<T> entityTableBuilder(final RestCall<Page<T>> apiCall) { | ||||||
|  |         return entityTableBuilder(apiCall.getEntityType().name(), apiCall); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     /** Get an new TableBuilder for specified page based RestCall. | ||||||
|  |      * | ||||||
|  |      * @param The name of the table to build | ||||||
|  |      * @param apiCall the SEB Server API RestCall that feeds the table with data | ||||||
|  |      * @param <T> the type of the Entity of the table | ||||||
|  |      * @return TableBuilder of specified type */ | ||||||
|  |     <T extends Entity> TableBuilder<T> entityTableBuilder( | ||||||
|  |             String name, | ||||||
|  |             RestCall<Page<T>> apiCall); | ||||||
| 
 | 
 | ||||||
|     /** Get a new PageActionBuilder for a given PageContext. |     /** Get a new PageActionBuilder for a given PageContext. | ||||||
|      * |      * | ||||||
|  |  | ||||||
|  | @ -231,10 +231,14 @@ public final class PageAction { | ||||||
|         return builder.toString(); |         return builder.toString(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public static PageAction applySingleSelection(final PageAction action) { |     public static PageAction applySingleSelectionAsEntityKey(final PageAction action) { | ||||||
|         return action.withEntityKey(action.getSingleSelection()); |         return action.withEntityKey(action.getSingleSelection()); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public static PageAction applySingleSelectionAsParentEntityKey(final PageAction action) { | ||||||
|  |         return action.withParentEntityKey(action.getSingleSelection()); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public static PageAction copyOf(final PageAction source) { |     public static PageAction copyOf(final PageAction source) { | ||||||
|         return new PageAction( |         return new PageAction( | ||||||
|                 source.definition, |                 source.definition, | ||||||
|  |  | ||||||
|  | @ -56,6 +56,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall.CallType; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall.CallType; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestService; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.AuthorizationContextHolder; | ||||||
|  | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | ||||||
| import ch.ethz.seb.sebserver.gui.table.EntityTable; | import ch.ethz.seb.sebserver.gui.table.EntityTable; | ||||||
| import ch.ethz.seb.sebserver.gui.table.TableBuilder; | import ch.ethz.seb.sebserver.gui.table.TableBuilder; | ||||||
| import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | ||||||
|  | @ -84,20 +85,20 @@ public class PageServiceImpl implements PageService { | ||||||
|     private final WidgetFactory widgetFactory; |     private final WidgetFactory widgetFactory; | ||||||
|     private final PolyglotPageService polyglotPageService; |     private final PolyglotPageService polyglotPageService; | ||||||
|     private final ResourceService resourceService; |     private final ResourceService resourceService; | ||||||
|     private final AuthorizationContextHolder authorizationContextHolder; |     private final CurrentUser currentUser; | ||||||
| 
 | 
 | ||||||
|     public PageServiceImpl( |     public PageServiceImpl( | ||||||
|             final JSONMapper jsonMapper, |             final JSONMapper jsonMapper, | ||||||
|             final WidgetFactory widgetFactory, |             final WidgetFactory widgetFactory, | ||||||
|             final PolyglotPageService polyglotPageService, |             final PolyglotPageService polyglotPageService, | ||||||
|             final ResourceService resourceService, |             final ResourceService resourceService, | ||||||
|             final AuthorizationContextHolder authorizationContextHolder) { |             final CurrentUser currentUser) { | ||||||
| 
 | 
 | ||||||
|         this.jsonMapper = jsonMapper; |         this.jsonMapper = jsonMapper; | ||||||
|         this.widgetFactory = widgetFactory; |         this.widgetFactory = widgetFactory; | ||||||
|         this.polyglotPageService = polyglotPageService; |         this.polyglotPageService = polyglotPageService; | ||||||
|         this.resourceService = resourceService; |         this.resourceService = resourceService; | ||||||
|         this.authorizationContextHolder = authorizationContextHolder; |         this.currentUser = currentUser; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  | @ -112,7 +113,7 @@ public class PageServiceImpl implements PageService { | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public AuthorizationContextHolder getAuthorizationContextHolder() { |     public AuthorizationContextHolder getAuthorizationContextHolder() { | ||||||
|         return this.authorizationContextHolder; |         return this.currentUser.getAuthorizationContextHolder(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  | @ -139,6 +140,11 @@ public class PageServiceImpl implements PageService { | ||||||
|         return this.resourceService.getRestService(); |         return this.resourceService.getRestService(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public CurrentUser getCurrentUser() { | ||||||
|  |         return this.currentUser; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public PageState getCurrentState() { |     public PageState getCurrentState() { | ||||||
|         try { |         try { | ||||||
|  | @ -317,8 +323,11 @@ public class PageServiceImpl implements PageService { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public <T extends Entity> TableBuilder<T> entityTableBuilder(final RestCall<Page<T>> apiCall) { |     public <T extends Entity> TableBuilder<T> entityTableBuilder( | ||||||
|         return new TableBuilder<>(this, apiCall); |             final String name, | ||||||
|  |             final RestCall<Page<T>> apiCall) { | ||||||
|  | 
 | ||||||
|  |         return new TableBuilder<>(name, this, apiCall); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|  | @ -326,9 +335,7 @@ public class PageServiceImpl implements PageService { | ||||||
|         this.clearState(); |         this.clearState(); | ||||||
| 
 | 
 | ||||||
|         try { |         try { | ||||||
|             final boolean logoutSuccessful = this.authorizationContextHolder |             final boolean logoutSuccessful = this.currentUser.logout(); | ||||||
|                     .getAuthorizationContext() |  | ||||||
|                     .logout(); |  | ||||||
| 
 | 
 | ||||||
|             if (!logoutSuccessful) { |             if (!logoutSuccessful) { | ||||||
|                 log.error("Failed to logout. See logfiles for more information"); |                 log.error("Failed to logout. See logfiles for more information"); | ||||||
|  |  | ||||||
|  | @ -45,9 +45,23 @@ public class CurrentUser { | ||||||
|     private final AuthorizationContextHolder authorizationContextHolder; |     private final AuthorizationContextHolder authorizationContextHolder; | ||||||
|     private SEBServerAuthorizationContext authContext = null; |     private SEBServerAuthorizationContext authContext = null; | ||||||
|     private Map<RoleTypeKey, Privilege> privileges = null; |     private Map<RoleTypeKey, Privilege> privileges = null; | ||||||
|  |     private final Map<String, String> attributes; | ||||||
| 
 | 
 | ||||||
|     public CurrentUser(final AuthorizationContextHolder authorizationContextHolder) { |     public CurrentUser(final AuthorizationContextHolder authorizationContextHolder) { | ||||||
|         this.authorizationContextHolder = authorizationContextHolder; |         this.authorizationContextHolder = authorizationContextHolder; | ||||||
|  |         this.attributes = new HashMap<>(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void putAttribute(final String name, final String value) { | ||||||
|  |         this.attributes.put(name, value); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public String getAttribute(final String name) { | ||||||
|  |         return this.attributes.get(name); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public AuthorizationContextHolder getAuthorizationContextHolder() { | ||||||
|  |         return this.authorizationContextHolder; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public UserInfo get() { |     public UserInfo get() { | ||||||
|  | @ -161,6 +175,19 @@ public class CurrentUser { | ||||||
|         this.authContext.refreshUser(userInfo); |         this.authContext.refreshUser(userInfo); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public boolean logout() { | ||||||
|  |         if (isAvailable()) { | ||||||
|  |             if (this.authContext.logout()) { | ||||||
|  |                 this.authContext = null; | ||||||
|  |                 return true; | ||||||
|  |             } else { | ||||||
|  |                 return false; | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             return this.authorizationContextHolder.getAuthorizationContext().logout(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private void updateContext() { |     private void updateContext() { | ||||||
|         if (this.authContext == null || !this.authContext.isValid()) { |         if (this.authContext == null || !this.authContext.isValid()) { | ||||||
|             this.authContext = this.authorizationContextHolder.getAuthorizationContext(); |             this.authContext = this.authorizationContextHolder.getAuthorizationContext(); | ||||||
|  |  | ||||||
|  | @ -57,6 +57,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser; | ||||||
| import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | ||||||
| import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; | import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; | ||||||
|  | import io.micrometer.core.instrument.util.StringUtils; | ||||||
| 
 | 
 | ||||||
| public class EntityTable<ROW extends Entity> { | public class EntityTable<ROW extends Entity> { | ||||||
| 
 | 
 | ||||||
|  | @ -67,6 +68,12 @@ public class EntityTable<ROW extends Entity> { | ||||||
|     private static final int HEADER_HEIGHT = 40; |     private static final int HEADER_HEIGHT = 40; | ||||||
|     private static final int ROW_HEIGHT = 25; |     private static final int ROW_HEIGHT = 25; | ||||||
| 
 | 
 | ||||||
|  |     private final String name; | ||||||
|  |     private final String filterAttrName; | ||||||
|  |     private final String sortAttrName; | ||||||
|  |     private final String sortOrderAttrName; | ||||||
|  |     private final String currentPageAttrName; | ||||||
|  | 
 | ||||||
|     final PageService pageService; |     final PageService pageService; | ||||||
|     final WidgetFactory widgetFactory; |     final WidgetFactory widgetFactory; | ||||||
|     final RestCall<Page<ROW>> restCall; |     final RestCall<Page<ROW>> restCall; | ||||||
|  | @ -92,6 +99,7 @@ public class EntityTable<ROW extends Entity> { | ||||||
|     boolean hideNavigation = false; |     boolean hideNavigation = false; | ||||||
| 
 | 
 | ||||||
|     EntityTable( |     EntityTable( | ||||||
|  |             final String name, | ||||||
|             final int type, |             final int type, | ||||||
|             final PageContext pageContext, |             final PageContext pageContext, | ||||||
|             final RestCall<Page<ROW>> restCall, |             final RestCall<Page<ROW>> restCall, | ||||||
|  | @ -105,6 +113,12 @@ public class EntityTable<ROW extends Entity> { | ||||||
|             final MultiValueMap<String, String> staticQueryParams, |             final MultiValueMap<String, String> staticQueryParams, | ||||||
|             final BiConsumer<TableItem, ROW> rowDecorator) { |             final BiConsumer<TableItem, ROW> rowDecorator) { | ||||||
| 
 | 
 | ||||||
|  |         this.name = name; | ||||||
|  |         this.filterAttrName = name + "_filter"; | ||||||
|  |         this.sortAttrName = name + "_sort"; | ||||||
|  |         this.sortOrderAttrName = name + "_sortOrder"; | ||||||
|  |         this.currentPageAttrName = name + "_currentPage"; | ||||||
|  | 
 | ||||||
|         this.composite = new Composite(pageContext.getParent(), type); |         this.composite = new Composite(pageContext.getParent(), type); | ||||||
|         this.pageService = pageService; |         this.pageService = pageService; | ||||||
|         this.i18nSupport = pageService.getI18nSupport(); |         this.i18nSupport = pageService.getI18nSupport(); | ||||||
|  | @ -125,10 +139,6 @@ public class EntityTable<ROW extends Entity> { | ||||||
|         this.composite.setLayoutData(gridData); |         this.composite.setLayoutData(gridData); | ||||||
|         this.staticQueryParams = staticQueryParams; |         this.staticQueryParams = staticQueryParams; | ||||||
|         this.rowDecorator = rowDecorator; |         this.rowDecorator = rowDecorator; | ||||||
| 
 |  | ||||||
| // TODO just for debugging, remove when tested |  | ||||||
| //        this.composite.setBackground(new Color(parent.getDisplay(), new RGB(0, 200, 0))); |  | ||||||
| 
 |  | ||||||
|         this.pageSize = pageSize; |         this.pageSize = pageSize; | ||||||
|         this.filter = |         this.filter = | ||||||
|                 columns |                 columns | ||||||
|  | @ -197,6 +207,9 @@ public class EntityTable<ROW extends Entity> { | ||||||
|         this.navigator = new TableNavigator(this); |         this.navigator = new TableNavigator(this); | ||||||
| 
 | 
 | ||||||
|         createTableColumns(); |         createTableColumns(); | ||||||
|  |         initCurrentPageFromUserAttr(); | ||||||
|  |         initFilterFromUserAttrs(); | ||||||
|  |         initSortFromUserAttr(); | ||||||
|         updateTableRows( |         updateTableRows( | ||||||
|                 this.pageNumber, |                 this.pageNumber, | ||||||
|                 this.pageSize, |                 this.pageSize, | ||||||
|  | @ -204,6 +217,10 @@ public class EntityTable<ROW extends Entity> { | ||||||
|                 this.sortOrder); |                 this.sortOrder); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     public String getName() { | ||||||
|  |         return this.name; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     public EntityType getEntityType() { |     public EntityType getEntityType() { | ||||||
|         if (this.restCall != null) { |         if (this.restCall != null) { | ||||||
|             return this.restCall.getEntityType(); |             return this.restCall.getEntityType(); | ||||||
|  | @ -245,15 +262,29 @@ public class EntityTable<ROW extends Entity> { | ||||||
|                 this.pageSize, |                 this.pageSize, | ||||||
|                 this.sortColumn, |                 this.sortColumn, | ||||||
|                 this.sortOrder); |                 this.sortOrder); | ||||||
|  | 
 | ||||||
|  |         updateCurrentPageAttr(pageSelection); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     public void reset() { | ||||||
|  |         this.applySort(null); | ||||||
|  |         this.table.setSortColumn(null); | ||||||
|  |         this.table.setSortDirection(SWT.NONE); | ||||||
|  |         applyFilter(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     public void applyFilter() { |     public void applyFilter() { | ||||||
|         try { |         try { | ||||||
|  | 
 | ||||||
|             updateTableRows( |             updateTableRows( | ||||||
|                     this.pageNumber, |                     this.pageNumber, | ||||||
|                     this.pageSize, |                     this.pageSize, | ||||||
|                     this.sortColumn, |                     this.sortColumn, | ||||||
|                     this.sortOrder); |                     this.sortOrder); | ||||||
|  | 
 | ||||||
|  |             updateFilterUserAttrs(); | ||||||
|  |             this.selectPage(0); | ||||||
|  | 
 | ||||||
|         } catch (final Exception e) { |         } catch (final Exception e) { | ||||||
|             log.error("Unexpected error while trying to apply filter: ", e); |             log.error("Unexpected error while trying to apply filter: ", e); | ||||||
|         } |         } | ||||||
|  | @ -269,6 +300,9 @@ public class EntityTable<ROW extends Entity> { | ||||||
|                     this.pageSize, |                     this.pageSize, | ||||||
|                     this.sortColumn, |                     this.sortColumn, | ||||||
|                     this.sortOrder); |                     this.sortOrder); | ||||||
|  | 
 | ||||||
|  |             updateSortUserAttr(); | ||||||
|  | 
 | ||||||
|         } catch (final Exception e) { |         } catch (final Exception e) { | ||||||
|             log.error("Unexpected error while trying to apply sort: ", e); |             log.error("Unexpected error while trying to apply sort: ", e); | ||||||
|         } |         } | ||||||
|  | @ -285,6 +319,9 @@ public class EntityTable<ROW extends Entity> { | ||||||
|                     this.pageSize, |                     this.pageSize, | ||||||
|                     this.sortColumn, |                     this.sortColumn, | ||||||
|                     this.sortOrder); |                     this.sortOrder); | ||||||
|  | 
 | ||||||
|  |             updateSortUserAttr(); | ||||||
|  | 
 | ||||||
|         } catch (final Exception e) { |         } catch (final Exception e) { | ||||||
|             log.error("Unexpected error while trying to apply sort: ", e); |             log.error("Unexpected error while trying to apply sort: ", e); | ||||||
|         } |         } | ||||||
|  | @ -366,6 +403,18 @@ public class EntityTable<ROW extends Entity> { | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private TableColumn getTableColumn(final String name) { | ||||||
|  |         return Arrays.asList(this.table.getColumns()) | ||||||
|  |                 .stream() | ||||||
|  |                 .filter(col -> { | ||||||
|  |                     @SuppressWarnings("unchecked") | ||||||
|  |                     final ColumnDefinition<ROW> def = (ColumnDefinition<ROW>) col.getData(COLUMN_DEFINITION); | ||||||
|  |                     return name.equals(def.columnName); | ||||||
|  |                 }) | ||||||
|  |                 .findFirst() | ||||||
|  |                 .orElse(null); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private void createTableColumns() { |     private void createTableColumns() { | ||||||
|         for (final ColumnDefinition<ROW> column : this.columns) { |         for (final ColumnDefinition<ROW> column : this.columns) { | ||||||
|             final TableColumn tableColumn = this.widgetFactory.tableColumnLocalized( |             final TableColumn tableColumn = this.widgetFactory.tableColumnLocalized( | ||||||
|  | @ -558,4 +607,91 @@ public class EntityTable<ROW extends Entity> { | ||||||
|         // TODO handle selection tool-tips on cell level |         // TODO handle selection tool-tips on cell level | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private void updateCurrentPageAttr(final int page) { | ||||||
|  |         try { | ||||||
|  |             this.pageService | ||||||
|  |                     .getCurrentUser() | ||||||
|  |                     .putAttribute(this.currentPageAttrName, String.valueOf(page)); | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             log.error("Failed to put current page attribute to current user attributes", e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void initCurrentPageFromUserAttr() { | ||||||
|  |         try { | ||||||
|  |             final String currentPage = this.pageService | ||||||
|  |                     .getCurrentUser() | ||||||
|  |                     .getAttribute(this.currentPageAttrName); | ||||||
|  |             if (StringUtils.isNotBlank(currentPage)) { | ||||||
|  |                 this.selectPage(Integer.parseInt(currentPage)); | ||||||
|  |             } | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             log.error("Failed to get sort attribute form current user attributes", e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void updateSortUserAttr() { | ||||||
|  |         try { | ||||||
|  |             this.pageService | ||||||
|  |                     .getCurrentUser() | ||||||
|  |                     .putAttribute(this.sortAttrName, this.sortColumn); | ||||||
|  |             this.pageService | ||||||
|  |                     .getCurrentUser() | ||||||
|  |                     .putAttribute(this.sortOrderAttrName, this.sortOrder.name()); | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             log.error("Failed to put sort attribute to current user attributes", e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void initSortFromUserAttr() { | ||||||
|  |         try { | ||||||
|  |             final String sort = this.pageService | ||||||
|  |                     .getCurrentUser() | ||||||
|  |                     .getAttribute(this.sortAttrName); | ||||||
|  |             if (StringUtils.isNotBlank(sort)) { | ||||||
|  |                 this.sortColumn = sort; | ||||||
|  |                 final TableColumn tableColumn = getTableColumn(sort); | ||||||
|  |                 if (tableColumn != null) { | ||||||
|  |                     this.table.setSortColumn(tableColumn); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             final String sortOrder = this.pageService | ||||||
|  |                     .getCurrentUser() | ||||||
|  |                     .getAttribute(this.sortOrderAttrName); | ||||||
|  |             if (StringUtils.isNotBlank(sortOrder)) { | ||||||
|  |                 this.sortOrder = PageSortOrder.valueOf(sortOrder); | ||||||
|  |                 this.table.setSortDirection(this.sortOrder == PageSortOrder.ASCENDING ? SWT.UP : SWT.DOWN); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             log.error("Failed to get sort attribute form current user attributes", e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void updateFilterUserAttrs() { | ||||||
|  |         if (this.filter != null) { | ||||||
|  |             try { | ||||||
|  |                 this.pageService | ||||||
|  |                         .getCurrentUser() | ||||||
|  |                         .putAttribute(this.filterAttrName, this.filter.getFilterAttributes()); | ||||||
|  |             } catch (final Exception e) { | ||||||
|  |                 log.error("Failed to put filter attributes to current user attributes", e); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     private void initFilterFromUserAttrs() { | ||||||
|  |         if (this.filter != null) { | ||||||
|  |             try { | ||||||
|  |                 this.filter.setFilterAttributes( | ||||||
|  |                         this.pageService | ||||||
|  |                                 .getCurrentUser() | ||||||
|  |                                 .getAttribute(this.filterAttrName)); | ||||||
|  |             } catch (final Exception e) { | ||||||
|  |                 log.error("Failed to get filter attributes form current user attributes", e); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||||
| 
 | 
 | ||||||
| public class TableBuilder<ROW extends Entity> { | public class TableBuilder<ROW extends Entity> { | ||||||
| 
 | 
 | ||||||
|  |     private final String name; | ||||||
|     private final PageService pageService; |     private final PageService pageService; | ||||||
|     final RestCall<Page<ROW>> restCall; |     final RestCall<Page<ROW>> restCall; | ||||||
|     private final MultiValueMap<String, String> staticQueryParams; |     private final MultiValueMap<String, String> staticQueryParams; | ||||||
|  | @ -43,9 +44,11 @@ public class TableBuilder<ROW extends Entity> { | ||||||
|     private BiConsumer<TableItem, ROW> rowDecorator; |     private BiConsumer<TableItem, ROW> rowDecorator; | ||||||
| 
 | 
 | ||||||
|     public TableBuilder( |     public TableBuilder( | ||||||
|  |             final String name, | ||||||
|             final PageService pageService, |             final PageService pageService, | ||||||
|             final RestCall<Page<ROW>> restCall) { |             final RestCall<Page<ROW>> restCall) { | ||||||
| 
 | 
 | ||||||
|  |         this.name = name; | ||||||
|         this.pageService = pageService; |         this.pageService = pageService; | ||||||
|         this.restCall = restCall; |         this.restCall = restCall; | ||||||
|         this.staticQueryParams = new LinkedMultiValueMap<>(); |         this.staticQueryParams = new LinkedMultiValueMap<>(); | ||||||
|  | @ -136,6 +139,7 @@ public class TableBuilder<ROW extends Entity> { | ||||||
| 
 | 
 | ||||||
|     public EntityTable<ROW> compose(final PageContext pageContext) { |     public EntityTable<ROW> compose(final PageContext pageContext) { | ||||||
|         return new EntityTable<>( |         return new EntityTable<>( | ||||||
|  |                 this.name, | ||||||
|                 this.type, |                 this.type, | ||||||
|                 pageContext, |                 pageContext, | ||||||
|                 this.restCall, |                 this.restCall, | ||||||
|  |  | ||||||
|  | @ -25,12 +25,15 @@ import org.eclipse.swt.widgets.DateTime; | ||||||
| import org.eclipse.swt.widgets.Label; | import org.eclipse.swt.widgets.Label; | ||||||
| import org.eclipse.swt.widgets.Text; | import org.eclipse.swt.widgets.Text; | ||||||
| import org.joda.time.DateTimeZone; | import org.joda.time.DateTimeZone; | ||||||
|  | import org.slf4j.Logger; | ||||||
|  | import org.slf4j.LoggerFactory; | ||||||
| import org.springframework.util.LinkedMultiValueMap; | import org.springframework.util.LinkedMultiValueMap; | ||||||
| import org.springframework.util.MultiValueMap; | import org.springframework.util.MultiValueMap; | ||||||
| 
 | 
 | ||||||
| import ch.ethz.seb.sebserver.gbl.Constants; | import ch.ethz.seb.sebserver.gbl.Constants; | ||||||
| import ch.ethz.seb.sebserver.gbl.model.Entity; | import ch.ethz.seb.sebserver.gbl.model.Entity; | ||||||
| import ch.ethz.seb.sebserver.gbl.util.Tuple; | import ch.ethz.seb.sebserver.gbl.util.Tuple; | ||||||
|  | import ch.ethz.seb.sebserver.gbl.util.Utils; | ||||||
| import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | import ch.ethz.seb.sebserver.gui.service.i18n.LocTextKey; | ||||||
| import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; | import ch.ethz.seb.sebserver.gui.table.ColumnDefinition.TableFilterAttribute; | ||||||
| import ch.ethz.seb.sebserver.gui.widget.Selection; | import ch.ethz.seb.sebserver.gui.widget.Selection; | ||||||
|  | @ -38,6 +41,8 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory.ImageIcon; | ||||||
| 
 | 
 | ||||||
| public class TableFilter<ROW extends Entity> { | public class TableFilter<ROW extends Entity> { | ||||||
| 
 | 
 | ||||||
|  |     private static final Logger log = LoggerFactory.getLogger(TableFilter.class); | ||||||
|  | 
 | ||||||
|     private static final LocTextKey DATE_FROM_TEXT = new LocTextKey("sebserver.overall.date.from"); |     private static final LocTextKey DATE_FROM_TEXT = new LocTextKey("sebserver.overall.date.from"); | ||||||
|     private static final LocTextKey DATE_TO_TEXT = new LocTextKey("sebserver.overall.date.to"); |     private static final LocTextKey DATE_TO_TEXT = new LocTextKey("sebserver.overall.date.to"); | ||||||
| 
 | 
 | ||||||
|  | @ -137,6 +142,50 @@ public class TableFilter<ROW extends Entity> { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     String getFilterAttributes() { | ||||||
|  |         final StringBuilder builder = this.components | ||||||
|  |                 .stream() | ||||||
|  |                 .reduce( | ||||||
|  |                         new StringBuilder(), | ||||||
|  |                         (sb, filter) -> sb | ||||||
|  |                                 .append(filter.attribute.columnName) | ||||||
|  |                                 .append(Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR) | ||||||
|  |                                 .append(filter.getValue()) | ||||||
|  |                                 .append(Constants.LIST_SEPARATOR), | ||||||
|  |                         (sb1, sb2) -> sb1.append(sb2)); | ||||||
|  |         if (builder.length() > 0) { | ||||||
|  |             builder.deleteCharAt(builder.length() - 1); | ||||||
|  |         } | ||||||
|  |         return builder.toString(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     void setFilterAttributes(final String attribute) { | ||||||
|  |         if (StringUtils.isBlank(attribute)) { | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         try { | ||||||
|  |             Arrays.asList(StringUtils.split( | ||||||
|  |                     attribute, | ||||||
|  |                     Constants.LIST_SEPARATOR_CHAR)) | ||||||
|  |                     .stream() | ||||||
|  |                     .map(nameValue -> StringUtils.split( | ||||||
|  |                             nameValue, | ||||||
|  |                             Constants.FORM_URL_ENCODED_NAME_VALUE_SEPARATOR)) | ||||||
|  |                     .forEach(nameValue -> { | ||||||
|  |                         this.components | ||||||
|  |                                 .stream() | ||||||
|  |                                 .filter(filter -> nameValue[0].equals(filter.attribute.columnName)) | ||||||
|  |                                 .findFirst() | ||||||
|  |                                 .ifPresent(filter -> filter.setValue((nameValue.length > 1) | ||||||
|  |                                         ? nameValue[1] | ||||||
|  |                                         : StringUtils.EMPTY)); | ||||||
|  |                     }); | ||||||
|  |         } catch (final Exception e) { | ||||||
|  |             log.error("Failed to set filter attributes: ", e); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     private void addActions() { |     private void addActions() { | ||||||
|         final Composite inner = new Composite(this.composite, SWT.NONE); |         final Composite inner = new Composite(this.composite, SWT.NONE); | ||||||
|         final GridLayout gridLayout = new GridLayout(2, true); |         final GridLayout gridLayout = new GridLayout(2, true); | ||||||
|  | @ -163,7 +212,7 @@ public class TableFilter<ROW extends Entity> { | ||||||
|                 new LocTextKey("sebserver.overall.action.filter.clear"), |                 new LocTextKey("sebserver.overall.action.filter.clear"), | ||||||
|                 event -> { |                 event -> { | ||||||
|                     reset(); |                     reset(); | ||||||
|                     this.entityTable.applyFilter(); |                     this.entityTable.reset(); | ||||||
|                 }); |                 }); | ||||||
|         imageButton2.setLayoutData(gridData); |         imageButton2.setLayoutData(gridData); | ||||||
|     } |     } | ||||||
|  | @ -196,6 +245,8 @@ public class TableFilter<ROW extends Entity> { | ||||||
| 
 | 
 | ||||||
|         abstract String getValue(); |         abstract String getValue(); | ||||||
| 
 | 
 | ||||||
|  |         abstract void setValue(String value); | ||||||
|  | 
 | ||||||
|         boolean adaptWidth(final int width) { |         boolean adaptWidth(final int width) { | ||||||
|             final int _width = width + CELL_WIDTH_ADJUSTMENT; |             final int _width = width + CELL_WIDTH_ADJUSTMENT; | ||||||
|             if (_width != this.rowData.width) { |             if (_width != this.rowData.width) { | ||||||
|  | @ -244,6 +295,10 @@ public class TableFilter<ROW extends Entity> { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         @Override | ||||||
|  |         void setValue(final String value) { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private class TextFilter extends FilterComponent { |     private class TextFilter extends FilterComponent { | ||||||
|  | @ -281,6 +336,13 @@ public class TableFilter<ROW extends Entity> { | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         @Override | ||||||
|  |         void setValue(final String value) { | ||||||
|  |             if (this.textInput != null) { | ||||||
|  |                 this.textInput.setText(value); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private class SelectionFilter extends FilterComponent { |     private class SelectionFilter extends FilterComponent { | ||||||
|  | @ -317,6 +379,9 @@ public class TableFilter<ROW extends Entity> { | ||||||
|         FilterComponent reset() { |         FilterComponent reset() { | ||||||
|             if (this.selector != null) { |             if (this.selector != null) { | ||||||
|                 this.selector.clear(); |                 this.selector.clear(); | ||||||
|  |                 if (StringUtils.isNotBlank(this.attribute.initValue)) { | ||||||
|  |                     this.selector.select(this.attribute.initValue); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             return this; |             return this; | ||||||
|         } |         } | ||||||
|  | @ -329,6 +394,13 @@ public class TableFilter<ROW extends Entity> { | ||||||
| 
 | 
 | ||||||
|             return null; |             return null; | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         void setValue(final String value) { | ||||||
|  |             if (this.selector != null) { | ||||||
|  |                 this.selector.select(value); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // NOTE: SWT DateTime month-number starting with 0 and joda DateTime with 1! |     // NOTE: SWT DateTime month-number starting with 0 and joda DateTime with 1! | ||||||
|  | @ -379,13 +451,24 @@ public class TableFilter<ROW extends Entity> { | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         @Override | ||||||
|  |         void setValue(final String value) { | ||||||
|  |             if (this.selector != null) { | ||||||
|  |                 try { | ||||||
|  |                     final org.joda.time.DateTime date = Utils.toDateTime(value); | ||||||
|  |                     this.selector.setDate(date.getYear(), date.getMonthOfYear() - 1, date.getDayOfMonth()); | ||||||
|  |                 } catch (final Exception e) { | ||||||
|  |                     log.error("Failed to set date filter attribute: ", e); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         @Override |         @Override | ||||||
|         boolean adaptWidth(final int width) { |         boolean adaptWidth(final int width) { | ||||||
|             // NOTE: for some unknown reason RWT acts differently on width-property for date selector |             // NOTE: for some unknown reason RWT acts differently on width-property for date selector | ||||||
|             //       this is to adjust date filter criteria to the list column width |             //       this is to adjust date filter criteria to the list column width | ||||||
|             return super.adaptWidth(width - 5); |             return super.adaptWidth(width - 5); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // NOTE: SWT DateTime month-number starting with 0 and joda DateTime with 1! |     // NOTE: SWT DateTime month-number starting with 0 and joda DateTime with 1! | ||||||
|  | @ -473,6 +556,23 @@ public class TableFilter<ROW extends Entity> { | ||||||
|                 return null; |                 return null; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         @Override | ||||||
|  |         void setValue(final String value) { | ||||||
|  |             if (this.fromSelector != null && this.toSelector != null) { | ||||||
|  |                 try { | ||||||
|  |                     final String[] split = StringUtils.split(value, Constants.EMBEDDED_LIST_SEPARATOR); | ||||||
|  |                     final org.joda.time.DateTime fromDate = Utils.toDateTime(split[0]); | ||||||
|  |                     final org.joda.time.DateTime toDate = Utils.toDateTime(split[1]); | ||||||
|  |                     this.fromSelector.setDate(fromDate.getYear(), fromDate.getMonthOfYear() - 1, | ||||||
|  |                             fromDate.getDayOfMonth()); | ||||||
|  |                     this.toSelector.setDate(toDate.getYear(), toDate.getMonthOfYear() - 1, toDate.getDayOfMonth()); | ||||||
|  |                 } catch (final Exception e) { | ||||||
|  |                     log.error("Failed to set date range filter attribute: ", e); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -106,6 +106,9 @@ public class InstitutionDAOImpl implements InstitutionDAO { | ||||||
|                 .and( |                 .and( | ||||||
|                         InstitutionRecordDynamicSqlSupport.name, |                         InstitutionRecordDynamicSqlSupport.name, | ||||||
|                         SqlBuilder.isLikeWhenPresent(filterMap.getName())) |                         SqlBuilder.isLikeWhenPresent(filterMap.getName())) | ||||||
|  |                 .and( | ||||||
|  |                         InstitutionRecordDynamicSqlSupport.urlSuffix, | ||||||
|  |                         SqlBuilder.isLikeWhenPresent(filterMap.getSQLWildcard(Institution.FILTER_ATTR_URL_SUFFIX))) | ||||||
|                 .build() |                 .build() | ||||||
|                 .execute() |                 .execute() | ||||||
|                 .stream() |                 .stream() | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ sebserver.gui.theme=css/sebserver.css | ||||||
| sebserver.gui.list.page.size=15 | sebserver.gui.list.page.size=15 | ||||||
| sebserver.gui.date.displayformat=yyyy-MM-dd HH:mm | sebserver.gui.date.displayformat=yyyy-MM-dd HH:mm | ||||||
| sebserver.gui.date.displayformat.timezone=|ZZ | sebserver.gui.date.displayformat.timezone=|ZZ | ||||||
| sebserver.gui.multilingual=true | sebserver.gui.multilingual=false | ||||||
| sebserver.gui.languages=en,de | sebserver.gui.languages=en,de | ||||||
| 
 | 
 | ||||||
| sebserver.gui.seb.client.config.download.filename=SEBClientSettings.seb | sebserver.gui.seb.client.config.download.filename=SEBClientSettings.seb | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ | ||||||
| 
 | 
 | ||||||
| sebserver.overall.version=SEB Server Version : {0} | sebserver.overall.version=SEB Server Version : {0} | ||||||
| sebserver.overall.help=Documentation | sebserver.overall.help=Documentation | ||||||
| sebserver.overall.help.link=https://www.safeexambrowser.org/news_en.html | sebserver.overall.help.link=https://seb-server.readthedocs.io/en/latest/# | ||||||
| 
 | 
 | ||||||
| sebserver.overall.message.leave.without.save=You have unsaved changes!\nAre you sure you want to leave the page?\The changes will be lost. | sebserver.overall.message.leave.without.save=You have unsaved changes!\nAre you sure you want to leave the page?\The changes will be lost. | ||||||
| sebserver.overall.upload=Please select a file | sebserver.overall.upload=Please select a file | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti