SEBSERV-45 finished rest of views with some missing attributes so far
This commit is contained in:
		
							parent
							
								
									fc07b5b80c
								
							
						
					
					
						commit
						eaf34ebeed
					
				
					 27 changed files with 480 additions and 112 deletions
				
			
		|  | @ -67,6 +67,7 @@ public final class API { | |||
|     public static final String CONFIGURATION_FOLLOWUP_PATH_SEGMENT = "/followup"; | ||||
|     public static final String CONFIGURATION_ENDPOINT = "/configuration"; | ||||
|     public static final String CONFIGURATION_SAVE_TO_HISTORY_PATH_SEGMENT = "/save_to_history"; | ||||
|     public static final String CONFIGURATION_UNDO_PATH_SEGMENT = "/undo"; | ||||
|     public static final String CONFIGURATION_RESTORE_FROM_HISTORY_PATH_SEGMENT = "/restore"; | ||||
| 
 | ||||
|     public static final String CONFIGURATION_VALUE_ENDPOINT = "/configuration_value"; | ||||
|  |  | |||
|  | @ -23,12 +23,14 @@ import org.springframework.stereotype.Component; | |||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.Constants; | ||||
| import ch.ethz.seb.sebserver.gbl.api.API; | ||||
| import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||
| import ch.ethz.seb.sebserver.gbl.model.EntityKey; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationNode; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.View; | ||||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||
| import ch.ethz.seb.sebserver.gbl.util.Utils; | ||||
| import ch.ethz.seb.sebserver.gui.content.action.ActionDefinition; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.impl.AttributeMapping; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.impl.ViewContext; | ||||
|  | @ -39,7 +41,10 @@ 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.seb.examconfig.GetConfigurations; | ||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.GetExamConfigNode; | ||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SaveExamConfigHistory; | ||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.seb.examconfig.SebExamConfigUndo; | ||||
| 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.widget.WidgetFactory; | ||||
| 
 | ||||
| @Lazy | ||||
|  | @ -50,7 +55,10 @@ public class SebExamConfigForm implements TemplateComposer { | |||
|     private static final Logger log = LoggerFactory.getLogger(SebExamConfigForm.class); | ||||
| 
 | ||||
|     private static final String VIEW_TEXT_KEY_PREFIX = "sebserver.examconfig.props.form.views."; | ||||
|     private static final String VIEW_TOOLTIP_TEXT_KEY_SUFFIX = ".tooltip"; | ||||
|     private static final String KEY_SAVE_TO_HISTORY_SUCCESS = | ||||
|             "sebserver.examconfig.action.saveToHistory.success"; | ||||
|     private static final String KEY_UNDO_SUCCESS = | ||||
|             "sebserver.examconfig.action.undo.success"; | ||||
| 
 | ||||
|     private static final LocTextKey TITLE_TEXT_KEY = | ||||
|             new LocTextKey("sebserver.examconfig.props.from.title"); | ||||
|  | @ -77,7 +85,6 @@ public class SebExamConfigForm implements TemplateComposer { | |||
|         final WidgetFactory widgetFactory = this.pageService.getWidgetFactory(); | ||||
| 
 | ||||
|         final EntityKey entityKey = pageContext.getEntityKey(); | ||||
|         final EntityKey parentEntityKey = pageContext.getParentEntityKey(); | ||||
| 
 | ||||
|         final Composite content = widgetFactory.defaultPageLayout( | ||||
|                 pageContext.getParent(), | ||||
|  | @ -131,6 +138,36 @@ public class SebExamConfigForm implements TemplateComposer { | |||
| 
 | ||||
|             this.examConfigurationService.initInputFieldValues(configuration.id, viewContexts); | ||||
| 
 | ||||
|             final GrantCheck examConfigGrant = this.currentUser.grantCheck(EntityType.CONFIGURATION_NODE); | ||||
|             this.pageService.pageActionBuilder(pageContext.clearEntityKeys()) | ||||
|                     .newAction(ActionDefinition.SEB_EXAM_CONFIG_SAVE_TO_HISTORY) | ||||
|                     .withEntityKey(entityKey) | ||||
|                     .withExec(action -> { | ||||
|                         this.restService.getBuilder(SaveExamConfigHistory.class) | ||||
|                                 .withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId()) | ||||
|                                 .call() | ||||
|                                 .onError(pageContext::notifyError) | ||||
|                                 .getOrThrow(); | ||||
|                         return action; | ||||
|                     }) | ||||
|                     .withSuccess(KEY_SAVE_TO_HISTORY_SUCCESS) | ||||
|                     .publishIf(() -> examConfigGrant.iw()) | ||||
| 
 | ||||
|                     .newAction(ActionDefinition.SEB_EXAM_CONFIG_UNDO) | ||||
|                     .withEntityKey(entityKey) | ||||
|                     .withExec(action -> { | ||||
|                         this.restService.getBuilder(SebExamConfigUndo.class) | ||||
|                                 .withURIVariable(API.PARAM_MODEL_ID, configuration.getModelId()) | ||||
|                                 .call() | ||||
|                                 .onError(pageContext::notifyError) | ||||
|                                 .getOrThrow(); | ||||
|                         return action; | ||||
|                     }) | ||||
|                     .withSuccess(KEY_UNDO_SUCCESS) | ||||
|                     .publishIf(() -> examConfigGrant.iw()) | ||||
| 
 | ||||
|             ; | ||||
| 
 | ||||
|         } catch (final Exception e) { | ||||
|             log.error("Unexpected error while trying to fetch exam configuration data and create views", e); | ||||
|             pageContext.notifyError(e); | ||||
|  |  | |||
|  | @ -345,6 +345,17 @@ public enum ActionDefinition { | |||
|             PageStateDefinition.SEB_EXAM_CONFIG_EDIT, | ||||
|             ActionCategory.SEB_EXAM_CONFIG_LIST), | ||||
| 
 | ||||
|     SEB_EXAM_CONFIG_SAVE_TO_HISTORY( | ||||
|             new LocTextKey("sebserver.examconfig.action.saveToHistory"), | ||||
|             ImageIcon.SAVE, | ||||
|             PageStateDefinition.SEB_EXAM_CONFIG_EDIT, | ||||
|             ActionCategory.SEB_EXAM_CONFIG_LIST), | ||||
|     SEB_EXAM_CONFIG_UNDO( | ||||
|             new LocTextKey("sebserver.examconfig.action.undo"), | ||||
|             ImageIcon.SAVE, | ||||
|             PageStateDefinition.SEB_EXAM_CONFIG_EDIT, | ||||
|             ActionCategory.SEB_EXAM_CONFIG_LIST), | ||||
| 
 | ||||
|     ; | ||||
| 
 | ||||
|     public final LocTextKey title; | ||||
|  |  | |||
|  | @ -8,8 +8,6 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.gui.service.examconfig.impl; | ||||
| 
 | ||||
| import static ch.ethz.seb.sebserver.gui.service.examconfig.impl.CellFieldBuilderAdapter.dummyBuilderAdapter; | ||||
| 
 | ||||
| import java.util.Collection; | ||||
| 
 | ||||
| import org.eclipse.swt.SWT; | ||||
|  | @ -28,23 +26,20 @@ import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | |||
| 
 | ||||
| interface CellFieldBuilderAdapter { | ||||
| 
 | ||||
|     static CellFieldBuilderAdapter DUMMY_BUILDER_ADAPTER = new CellFieldBuilderAdapter() { | ||||
|         @Override | ||||
|         public void createCell(final ViewGridBuilder builder) { | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public String toString() { | ||||
|             return "[DUMMY]"; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     void createCell(ViewGridBuilder builder); | ||||
| 
 | ||||
|     default void balanceGrid(final CellFieldBuilderAdapter[][] grid, final int x, final int y) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     static CellFieldBuilderAdapter dummyBuilderAdapter() { | ||||
|         return new CellFieldBuilderAdapter() { | ||||
|             @Override | ||||
|             public void createCell(final ViewGridBuilder builder) { | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public String toString() { | ||||
|                 return "[DUMMY]"; | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     static CellFieldBuilderAdapter fieldBuilderAdapter( | ||||
|  | @ -127,7 +122,7 @@ interface CellFieldBuilderAdapter { | |||
|                     int xpos = x - 1; | ||||
|                     while (xpos >= 0 && grid[y][xpos] == null && span < orientation.width) { | ||||
|                         grid[y][xpos] = this; | ||||
|                         grid[y][xpos + 1] = dummyBuilderAdapter(); | ||||
|                         grid[y][xpos + 1] = DUMMY_BUILDER_ADAPTER; | ||||
|                         this.span++; | ||||
|                         xpos--; | ||||
|                     } | ||||
|  | @ -198,13 +193,20 @@ interface CellFieldBuilderAdapter { | |||
|             final WidgetFactory widgetFactory = builder.examConfigurationService.getWidgetFactory(); | ||||
|             final Orientation o = this.orientationsOfGroup.stream().findFirst().get(); | ||||
|             final LocTextKey groupLabelKey = new LocTextKey( | ||||
|                     ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + o.groupId, | ||||
|                     ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + | ||||
|                             o.groupId, | ||||
|                     o.groupId); | ||||
|             final LocTextKey groupTooltipKey = new LocTextKey( | ||||
|                     ExamConfigurationService.GROUP_LABEL_LOC_TEXT_PREFIX + | ||||
|                             o.groupId + | ||||
|                             ExamConfigurationService.TOOL_TIP_SUFFIX, | ||||
|                     o.groupId); | ||||
| 
 | ||||
|             final Group group = widgetFactory.groupLocalized( | ||||
|                     builder.parent, | ||||
|                     this.width, | ||||
|                     groupLabelKey); | ||||
|                     groupLabelKey, | ||||
|                     groupTooltipKey); | ||||
|             group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, this.width, this.height)); | ||||
| 
 | ||||
|             final ViewGridBuilder groupBuilder = new ViewGridBuilder( | ||||
|  |  | |||
|  | @ -20,7 +20,6 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; | |||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; | ||||
| import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; | ||||
| import ch.ethz.seb.sebserver.gui.widget.MultiSelectionCheckbox; | ||||
| import ch.ethz.seb.sebserver.gui.widget.Selection; | ||||
| import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | ||||
|  | @ -50,7 +49,6 @@ public class MultiCheckboxSelection extends SelectionFieldBuilder implements Inp | |||
|             final ConfigurationAttribute attribute, | ||||
|             final ViewContext viewContext) { | ||||
| 
 | ||||
|         final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport(); | ||||
|         final Orientation orientation = viewContext | ||||
|                 .getOrientation(attribute.id); | ||||
|         final Composite innerGrid = InputFieldBuilder | ||||
|  |  | |||
|  | @ -21,7 +21,6 @@ import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; | |||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; | ||||
| import ch.ethz.seb.sebserver.gui.service.i18n.I18nSupport; | ||||
| import ch.ethz.seb.sebserver.gui.widget.RadioSelection; | ||||
| import ch.ethz.seb.sebserver.gui.widget.Selection; | ||||
| import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; | ||||
|  | @ -52,7 +51,6 @@ public class RadioSelectionFieldBuilder extends SelectionFieldBuilder implements | |||
|             final ConfigurationAttribute attribute, | ||||
|             final ViewContext viewContext) { | ||||
| 
 | ||||
|         final I18nSupport i18nSupport = this.widgetFactory.getI18nSupport(); | ||||
|         final Orientation orientation = viewContext | ||||
|                 .getOrientation(attribute.id); | ||||
|         final Composite innerGrid = InputFieldBuilder | ||||
|  |  | |||
|  | @ -24,6 +24,7 @@ import ch.ethz.seb.sebserver.gbl.model.Domain; | |||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues.TableValue; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.Orientation; | ||||
| import ch.ethz.seb.sebserver.gui.service.ResourceService; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.ExamConfigurationService; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.InputField; | ||||
| import ch.ethz.seb.sebserver.gui.service.examconfig.InputFieldBuilder; | ||||
|  | @ -191,12 +192,10 @@ public class TableContext { | |||
|             switch (attribute.type) { | ||||
|                 case CHECKBOX: { | ||||
|                     return BooleanUtils.toBoolean(tableValue.value) | ||||
|                             ? "Active" | ||||
|                             : "Inactive"; | ||||
|                             ? this.viewContext.i18nSupport.getText(ResourceService.ACTIVE_TEXT_KEY) | ||||
|                             : this.viewContext.i18nSupport.getText(ResourceService.INACTIVE_TEXT_KEY); | ||||
|                 } | ||||
|                 case SINGLE_SELECTION: { | ||||
|                     final ConfigurationAttribute tableAttr = | ||||
|                             this.viewContext.attributeMapping.getAttribute(attribute.parentId); | ||||
|                     final String key = ExamConfigurationService.ATTRIBUTE_LABEL_LOC_TEXT_PREFIX + | ||||
|                             attribute.getName() + "." + | ||||
|                             tableValue.value; | ||||
|  |  | |||
|  | @ -278,7 +278,7 @@ public class TableFieldBuilder implements InputFieldBuilder { | |||
|         } | ||||
| 
 | ||||
|         private void addTableRow(final Map<Long, TableValue> rowValues) { | ||||
|             final TableItem tableItem = new TableItem(this.control, SWT.NONE); | ||||
|             new TableItem(this.control, SWT.NONE); | ||||
|             applyTableRowValues(this.values.size() - 1); | ||||
| 
 | ||||
|             // TODO try to add delete button within table row? | ||||
|  |  | |||
|  | @ -83,10 +83,10 @@ public class TableRowFormBuilder implements ModalInputDialogComposer<Map<Long, T | |||
|             final Composite parent, | ||||
|             final ConfigurationAttribute attribute) { | ||||
| 
 | ||||
| //        if (attribute.type == AttributeType.TABLE) { | ||||
| //            throw new UnsupportedOperationException( | ||||
| //                    "Table type is currently not supported within a table row form view!"); | ||||
| //        } | ||||
|         if (attribute.type == AttributeType.TABLE) { | ||||
|             throw new UnsupportedOperationException( | ||||
|                     "Table type is currently not supported within a table row form view!"); | ||||
|         } | ||||
| 
 | ||||
|         final Orientation orientation = this.tableContext | ||||
|                 .getOrientation(attribute.id); | ||||
|  |  | |||
|  | @ -161,8 +161,8 @@ public class ViewGridBuilder { | |||
|     } | ||||
| 
 | ||||
|     void compose() { | ||||
|         if (log.isDebugEnabled()) { | ||||
|             log.debug("Compose grid view: \n" + gridToString()); | ||||
|         if (log.isTraceEnabled()) { | ||||
|             log.trace("Compose grid view: \n" + gridToString()); | ||||
|         } | ||||
| 
 | ||||
|         // balance grid (optimize span and grab empty spaces for labels where applicable) | ||||
|  | @ -181,7 +181,7 @@ public class ViewGridBuilder { | |||
|                     final GridData gridData = new GridData(SWT.FILL, SWT.FILL, true, false); | ||||
|                     gridData.verticalIndent = 8; | ||||
|                     empty.setLayoutData(gridData); | ||||
|                     empty.setText("" /* "empty " + x + " " + y */); | ||||
|                     empty.setText(StringUtils.EMPTY /* "empty " + x + " " + y */); | ||||
|                 } else { | ||||
|                     this.grid[y][x].createCell(this); | ||||
|                 } | ||||
|  | @ -194,7 +194,11 @@ public class ViewGridBuilder { | |||
|         final int upperBoundY = y + height; | ||||
|         for (int _y = y; _y < upperBoundY; _y++) { | ||||
|             for (int _x = x; _x < upperBoundX; _x++) { | ||||
|                 this.grid[_y][_x] = CellFieldBuilderAdapter.dummyBuilderAdapter(); | ||||
|                 if (_y < 0 || _x < 0 || _y >= this.grid.length || _x >= this.grid[_y].length) { | ||||
|                     log.warn("Out of bounds: {} {}", _x, _y); | ||||
|                     continue; | ||||
|                 } | ||||
|                 this.grid[_y][_x] = CellFieldBuilderAdapter.DUMMY_BUILDER_ADAPTER; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  |  | |||
|  | @ -41,6 +41,15 @@ public interface I18nSupport { | |||
|      * @return date/time column title suffix for current user */ | ||||
|     String getUsersTimeZoneTitleSuffix(); | ||||
| 
 | ||||
|     /** Get localized text of specified key for currently set Locale. | ||||
|      * | ||||
|      * @param key LocTextKey instance | ||||
|      * @param def default text | ||||
|      * @return the text in current language parsed from localized text */ | ||||
|     default String getText(final LocTextKey key, final String def) { | ||||
|         return getText(key.name, def, key.args); | ||||
|     } | ||||
| 
 | ||||
|     /** Get localized text of specified key for currently set Locale. | ||||
|      * | ||||
|      * @param key LocTextKey instance | ||||
|  |  | |||
|  | @ -31,6 +31,8 @@ public final class PageAction { | |||
| 
 | ||||
|     private static final Logger log = LoggerFactory.getLogger(PageAction.class); | ||||
| 
 | ||||
|     public static final LocTextKey SUCCESS_MSG_TITLE = new LocTextKey("sebserver.page.message"); | ||||
| 
 | ||||
|     public final ActionDefinition definition; | ||||
|     private final Supplier<LocTextKey> confirm; | ||||
|     final LocTextKey successMessage; | ||||
|  | @ -126,7 +128,11 @@ public final class PageAction { | |||
|     private Result<PageAction> exec() { | ||||
|         try { | ||||
| 
 | ||||
|             return Result.of(this.exec.apply(this)); | ||||
|             final PageAction apply = this.exec.apply(this); | ||||
|             if (this.successMessage != null) { | ||||
|                 apply.pageContext.publishPageMessage(SUCCESS_MSG_TITLE, this.successMessage); | ||||
|             } | ||||
|             return Result.of(apply); | ||||
| 
 | ||||
|         } catch (final PageMessageException pme) { | ||||
|             PageAction.this.pageContext.publishPageMessage(pme); | ||||
|  |  | |||
|  | @ -0,0 +1,42 @@ | |||
| /* | ||||
|  * 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.seb.examconfig; | ||||
| 
 | ||||
| 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.API; | ||||
| import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; | ||||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||
| 
 | ||||
| @Lazy | ||||
| @Component | ||||
| @GuiProfile | ||||
| public class SaveExamConfigHistory extends RestCall<Configuration> { | ||||
| 
 | ||||
|     protected SaveExamConfigHistory() { | ||||
|         super(new TypeKey<>( | ||||
|                 CallType.SAVE, | ||||
|                 EntityType.CONFIGURATION, | ||||
|                 new TypeReference<Configuration>() { | ||||
|                 }), | ||||
|                 HttpMethod.POST, | ||||
|                 MediaType.APPLICATION_FORM_URLENCODED, | ||||
|                 API.CONFIGURATION_ENDPOINT + | ||||
|                         API.CONFIGURATION_SAVE_TO_HISTORY_PATH_SEGMENT + | ||||
|                         API.MODEL_ID_VAR_PATH_SEGMENT); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,42 @@ | |||
| /* | ||||
|  * 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.seb.examconfig; | ||||
| 
 | ||||
| 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.API; | ||||
| import ch.ethz.seb.sebserver.gbl.api.EntityType; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.Configuration; | ||||
| import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; | ||||
| import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.RestCall; | ||||
| 
 | ||||
| @Lazy | ||||
| @Component | ||||
| @GuiProfile | ||||
| public class SebExamConfigUndo extends RestCall<Configuration> { | ||||
| 
 | ||||
|     protected SebExamConfigUndo() { | ||||
|         super(new TypeKey<>( | ||||
|                 CallType.SAVE, | ||||
|                 EntityType.CONFIGURATION, | ||||
|                 new TypeReference<Configuration>() { | ||||
|                 }), | ||||
|                 HttpMethod.POST, | ||||
|                 MediaType.APPLICATION_FORM_URLENCODED, | ||||
|                 API.CONFIGURATION_ENDPOINT + | ||||
|                         API.CONFIGURATION_UNDO_PATH_SEGMENT + | ||||
|                         API.MODEL_ID_VAR_PATH_SEGMENT); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -60,7 +60,6 @@ public class EntityTable<ROW extends Entity> { | |||
|     final I18nSupport i18nSupport; | ||||
| 
 | ||||
|     final List<ColumnDefinition<ROW>> columns; | ||||
|     final List<TableRowAction> actions; | ||||
|     final LocTextKey emptyMessage; | ||||
| 
 | ||||
|     final Composite composite; | ||||
|  | @ -82,7 +81,6 @@ public class EntityTable<ROW extends Entity> { | |||
|             final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter, | ||||
|             final PageService pageService, | ||||
|             final List<ColumnDefinition<ROW>> columns, | ||||
|             final List<TableRowAction> actions, | ||||
|             final int pageSize, | ||||
|             final LocTextKey emptyMessage, | ||||
|             final Function<EntityTable<ROW>, PageAction> defaultActionFunction, | ||||
|  | @ -95,7 +93,6 @@ public class EntityTable<ROW extends Entity> { | |||
|         this.restCall = restCall; | ||||
|         this.restCallAdapter = (restCallAdapter != null) ? restCallAdapter : Function.identity(); | ||||
|         this.columns = Utils.immutableListOf(columns); | ||||
|         this.actions = Utils.immutableListOf(actions); | ||||
|         this.emptyMessage = emptyMessage; | ||||
|         this.hideNavigation = hideNavigation; | ||||
| 
 | ||||
|  | @ -324,9 +321,6 @@ public class EntityTable<ROW extends Entity> { | |||
|                 setValueToCell(item, index, column.valueSupplier.apply(row)); | ||||
|                 index++; | ||||
|             } | ||||
|             if (this.actions != null) { | ||||
|                 // TODO?? | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         return page; | ||||
|  |  | |||
|  | @ -29,13 +29,12 @@ public class TableBuilder<ROW extends Entity> { | |||
|     private final PageService pageService; | ||||
|     final RestCall<Page<ROW>> restCall; | ||||
|     final List<ColumnDefinition<ROW>> columns = new ArrayList<>(); | ||||
|     final List<TableRowAction> actions = new ArrayList<>(); | ||||
|     LocTextKey emptyMessage; | ||||
|     private Function<EntityTable<ROW>, PageAction> defaultActionFunction; | ||||
|     private int pageSize = -1; | ||||
|     private int type = SWT.NONE; | ||||
|     private boolean hideNavigation = false; | ||||
|     private Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter;; | ||||
|     private Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> restCallAdapter; | ||||
| 
 | ||||
|     public TableBuilder( | ||||
|             final PageService pageService, | ||||
|  | @ -75,11 +74,6 @@ public class TableBuilder<ROW extends Entity> { | |||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public TableBuilder<ROW> withAction(final TableRowAction action) { | ||||
|         this.actions.add(action); | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public TableBuilder<ROW> withRestCallAdapter( | ||||
|             final Function<RestCall<Page<ROW>>.RestCallBuilder, RestCall<Page<ROW>>.RestCallBuilder> adapter) { | ||||
|         this.restCallAdapter = adapter; | ||||
|  | @ -120,7 +114,6 @@ public class TableBuilder<ROW extends Entity> { | |||
|                 this.restCallAdapter, | ||||
|                 this.pageService, | ||||
|                 this.columns, | ||||
|                 this.actions, | ||||
|                 this.pageSize, | ||||
|                 this.emptyMessage, | ||||
|                 this.defaultActionFunction, | ||||
|  |  | |||
|  | @ -1,13 +0,0 @@ | |||
| /* | ||||
|  * Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET) | ||||
|  *  | ||||
|  * This Source Code Form is subject to the terms of the Mozilla Public | ||||
|  * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||||
|  */ | ||||
| 
 | ||||
| package ch.ethz.seb.sebserver.gui.table; | ||||
| 
 | ||||
| public class TableRowAction { | ||||
| 
 | ||||
| } | ||||
|  | @ -17,6 +17,7 @@ import java.util.Locale; | |||
| import java.util.function.Consumer; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| import org.apache.commons.lang3.StringUtils; | ||||
| import org.eclipse.rap.rwt.RWT; | ||||
| import org.eclipse.swt.SWT; | ||||
| import org.eclipse.swt.graphics.Device; | ||||
|  | @ -309,6 +310,15 @@ public class WidgetFactory { | |||
|             final int columns, | ||||
|             final LocTextKey locTextKey) { | ||||
| 
 | ||||
|         return groupLocalized(parent, columns, locTextKey, null); | ||||
|     } | ||||
| 
 | ||||
|     public Group groupLocalized( | ||||
|             final Composite parent, | ||||
|             final int columns, | ||||
|             final LocTextKey locTextKey, | ||||
|             final LocTextKey locTooltipKey) { | ||||
| 
 | ||||
|         final Group group = new Group(parent, SWT.NONE); | ||||
|         final GridLayout gridLayout = new GridLayout(columns, true); | ||||
|         gridLayout.verticalSpacing = 0; | ||||
|  | @ -316,7 +326,7 @@ public class WidgetFactory { | |||
|         gridLayout.marginHeight = 0; | ||||
|         group.setLayout(gridLayout); | ||||
| 
 | ||||
|         this.injectI18n(group, locTextKey); | ||||
|         this.injectI18n(group, locTextKey, locTooltipKey); | ||||
|         return group; | ||||
|     } | ||||
| 
 | ||||
|  | @ -521,8 +531,8 @@ public class WidgetFactory { | |||
|         labelFunction.accept(label); | ||||
|     } | ||||
| 
 | ||||
|     public void injectI18n(final Group group, final LocTextKey locTextKey) { | ||||
|         final Consumer<Group> groupFunction = groupFunction(locTextKey, null, this.i18nSupport); | ||||
|     public void injectI18n(final Group group, final LocTextKey locTextKey, final LocTextKey locTooltipKey) { | ||||
|         final Consumer<Group> groupFunction = groupFunction(locTextKey, locTooltipKey, this.i18nSupport); | ||||
|         group.setData(POLYGLOT_WIDGET_FUNCTION_KEY, groupFunction); | ||||
|         groupFunction.accept(group); | ||||
|     } | ||||
|  | @ -656,7 +666,7 @@ public class WidgetFactory { | |||
|                 group.setText(i18nSupport.getText(locTextKey)); | ||||
|             } | ||||
|             if (locToolTipKey != null) { | ||||
|                 group.setToolTipText(i18nSupport.getText(locToolTipKey)); | ||||
|                 group.setToolTipText(i18nSupport.getText(locToolTipKey, StringUtils.EMPTY)); | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
|  |  | |||
|  | @ -42,6 +42,8 @@ public interface ConfigurationDAO extends EntityDAO<Configuration, Configuration | |||
|      * @return the new follow-up Configuration model */ | ||||
|     Result<Configuration> saveToHistory(Long configurationNodeId); | ||||
| 
 | ||||
|     Result<Configuration> undo(Long configurationNodeId); | ||||
| 
 | ||||
|     /** Restores the current follow-up Configuration to the values of a given Configuration | ||||
|      * in the history of the specified ConfigurationNode. | ||||
|      * | ||||
|  |  | |||
|  | @ -165,18 +165,7 @@ public class ConfigurationDAOImpl implements ConfigurationDAO { | |||
|         return Result.tryCatch(() -> { | ||||
| 
 | ||||
|             // get follow-up configuration... | ||||
|             final ConfigurationRecord followupConfig = this.configurationRecordMapper | ||||
|                     .selectByExample() | ||||
|                     .where( | ||||
|                             ConfigurationRecordDynamicSqlSupport.configurationNodeId, | ||||
|                             isEqualTo(configurationNodeId)) | ||||
|                     .and( | ||||
|                             ConfigurationRecordDynamicSqlSupport.followup, | ||||
|                             isEqualTo(BooleanUtils.toInteger(true))) | ||||
|                     .build() | ||||
|                     .execute() | ||||
|                     .stream() | ||||
|                     .collect(Utils.toSingleton()); | ||||
|             final ConfigurationRecord followupConfig = getFollowupConfigurationRecord(configurationNodeId); | ||||
| 
 | ||||
|             // with actual attribute values | ||||
|             final List<ConfigurationValueRecord> allValues = this.configurationValueRecordMapper | ||||
|  | @ -239,6 +228,41 @@ public class ConfigurationDAOImpl implements ConfigurationDAO { | |||
|                 .onError(TransactionHandler::rollback); | ||||
|     } | ||||
| 
 | ||||
|     private ConfigurationRecord getFollowupConfigurationRecord(final Long configurationNodeId) { | ||||
|         return this.configurationRecordMapper | ||||
|                 .selectByExample() | ||||
|                 .where( | ||||
|                         ConfigurationRecordDynamicSqlSupport.configurationNodeId, | ||||
|                         isEqualTo(configurationNodeId)) | ||||
|                 .and( | ||||
|                         ConfigurationRecordDynamicSqlSupport.followup, | ||||
|                         isEqualTo(BooleanUtils.toInteger(true))) | ||||
|                 .build() | ||||
|                 .execute() | ||||
|                 .stream() | ||||
|                 .collect(Utils.toSingleton()); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public Result<Configuration> undo(final Long configurationNodeId) { | ||||
|         return Result.tryCatch(() -> { | ||||
|             // get all configurations of the node | ||||
|             final List<ConfigurationRecord> configs = this.configurationRecordMapper | ||||
|                     .selectByExample() | ||||
|                     .where( | ||||
|                             ConfigurationRecordDynamicSqlSupport.configurationNodeId, | ||||
|                             isEqualTo(configurationNodeId)) | ||||
|                     .orderBy(ConfigurationRecordDynamicSqlSupport.versionDate) | ||||
|                     .build() | ||||
|                     .execute(); | ||||
| 
 | ||||
|             return configs.get(configs.size() - 1); | ||||
|         }) | ||||
|                 .flatMap(rec -> restoreToVersion(configurationNodeId, rec.getId())) | ||||
|                 .onError(TransactionHandler::rollback); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @Transactional | ||||
|     public Result<Configuration> restoreToVersion(final Long configurationNodeId, final Long configId) { | ||||
|  | @ -268,28 +292,17 @@ public class ConfigurationDAOImpl implements ConfigurationDAO { | |||
|                     .execute(); | ||||
| 
 | ||||
|             // get follow-up configuration id | ||||
|             final ConfigurationRecord followup = this.configurationRecordMapper | ||||
|                     .selectByExample() | ||||
|                     .where( | ||||
|                             ConfigurationRecordDynamicSqlSupport.configurationNodeId, | ||||
|                             isEqualTo(configurationNodeId)) | ||||
|                     .and( | ||||
|                             ConfigurationRecordDynamicSqlSupport.followup, | ||||
|                             isEqualTo(BooleanUtils.toInteger(true))) | ||||
|                     .build() | ||||
|                     .execute() | ||||
|                     .stream() | ||||
|                     .collect(Utils.toSingleton()); | ||||
|             final ConfigurationRecord followup = getFollowupConfigurationRecord(configurationNodeId); | ||||
| 
 | ||||
|             // restore all current values of the follow-up with historic values | ||||
|             // TODO batch here for better performance | ||||
|             historicValues.stream() | ||||
|                     .map(historicValRec -> new ConfigurationValueRecord( | ||||
|                             null, | ||||
|                             null, | ||||
|                             null, | ||||
|                             followup.getInstitutionId(), | ||||
|                             followup.getId(), | ||||
|                             historicValRec.getConfigurationAttributeId(), | ||||
|                             null, | ||||
|                             historicValRec.getListIndex(), | ||||
|                             historicValRec.getValue(), | ||||
|                             historicValRec.getText())) | ||||
|                     .forEach(newValRec -> this.configurationValueRecordMapper | ||||
|  |  | |||
|  | @ -8,6 +8,8 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig; | ||||
| 
 | ||||
| import java.io.OutputStream; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationTableValues; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; | ||||
| 
 | ||||
|  | @ -17,4 +19,8 @@ public interface SebExamConfigService { | |||
| 
 | ||||
|     void validate(ConfigurationTableValues tableValue); | ||||
| 
 | ||||
|     void exportXML(OutputStream out, Long configurationNodeId); | ||||
| 
 | ||||
|     void exportForExam(OutputStream out, Long configExamMappingId); | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,25 @@ | |||
| /* | ||||
|  * 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.webservice.servicelayer.sebconfig; | ||||
| 
 | ||||
| import java.io.OutputStream; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; | ||||
| 
 | ||||
| public interface XMLValueConverter { | ||||
| 
 | ||||
|     String name(); | ||||
| 
 | ||||
|     void convertToXML( | ||||
|             OutputStream out, | ||||
|             ConfigurationAttribute attribute, | ||||
|             ConfigurationValue value); | ||||
| 
 | ||||
| } | ||||
|  | @ -8,6 +8,7 @@ | |||
| 
 | ||||
| package ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.impl; | ||||
| 
 | ||||
| import java.io.OutputStream; | ||||
| import java.util.Collection; | ||||
| 
 | ||||
| import org.slf4j.Logger; | ||||
|  | @ -22,6 +23,7 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | |||
| import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ConfigurationAttributeDAO; | ||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ConfigurationValueValidator; | ||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.SebExamConfigService; | ||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.XMLValueConverter; | ||||
| 
 | ||||
| @Lazy | ||||
| @Service | ||||
|  | @ -32,13 +34,16 @@ public class SebExamConfigServiceImpl implements SebExamConfigService { | |||
| 
 | ||||
|     private final ConfigurationAttributeDAO configurationAttributeDAO; | ||||
|     private final Collection<ConfigurationValueValidator> validators; | ||||
|     private final Collection<XMLValueConverter> converters; | ||||
| 
 | ||||
|     protected SebExamConfigServiceImpl( | ||||
|             final ConfigurationAttributeDAO configurationAttributeDAO, | ||||
|             final Collection<ConfigurationValueValidator> validators) { | ||||
|             final Collection<ConfigurationValueValidator> validators, | ||||
|             final Collection<XMLValueConverter> converters) { | ||||
| 
 | ||||
|         this.configurationAttributeDAO = configurationAttributeDAO; | ||||
|         this.validators = validators; | ||||
|         this.converters = converters; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|  | @ -65,4 +70,16 @@ public class SebExamConfigServiceImpl implements SebExamConfigService { | |||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void exportXML(final OutputStream out, final Long configurationNodeId) { | ||||
|         // TODO Auto-generated method stub | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void exportForExam(final OutputStream out, final Long configExamMappingId) { | ||||
|         // TODO Auto-generated method stub | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,43 @@ | |||
| /* | ||||
|  * 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.webservice.servicelayer.sebconfig.impl.converter; | ||||
| 
 | ||||
| import java.io.OutputStream; | ||||
| 
 | ||||
| import org.springframework.context.annotation.Lazy; | ||||
| import org.springframework.stereotype.Component; | ||||
| 
 | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationAttribute; | ||||
| import ch.ethz.seb.sebserver.gbl.model.sebconfig.ConfigurationValue; | ||||
| import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; | ||||
| import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.XMLValueConverter; | ||||
| 
 | ||||
| @Lazy | ||||
| @Component | ||||
| @WebServiceProfile | ||||
| public class KioskModeConverter implements XMLValueConverter { | ||||
| 
 | ||||
|     public static final String NAME = "KioskModeConverter"; | ||||
| 
 | ||||
|     @Override | ||||
|     public String name() { | ||||
|         return NAME; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void convertToXML( | ||||
|             final OutputStream out, | ||||
|             final ConfigurationAttribute attribute, | ||||
|             final ConfigurationValue value) { | ||||
| 
 | ||||
|         // TODO Auto-generated method stub | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
|  | @ -64,24 +64,37 @@ public class ConfigurationController extends EntityController<Configuration, Con | |||
|             method = RequestMethod.POST, | ||||
|             consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, | ||||
|             produces = MediaType.APPLICATION_JSON_UTF8_VALUE) | ||||
|     public Configuration saveToHistory(@PathVariable final String configId) { | ||||
|     public Configuration saveToHistory(@PathVariable final String modelId) { | ||||
| 
 | ||||
|         return this.entityDAO.byModelId(configId) | ||||
|         return this.entityDAO.byModelId(modelId) | ||||
|                 .flatMap(this::checkModifyAccess) | ||||
|                 .flatMap(config -> this.configurationDAO.saveToHistory(config.configurationNodeId)) | ||||
|                 .getOrThrow(); | ||||
|     } | ||||
| 
 | ||||
|     @RequestMapping( | ||||
|             path = API.CONFIGURATION_UNDO_PATH_SEGMENT + API.MODEL_ID_VAR_PATH_SEGMENT, | ||||
|             method = RequestMethod.POST, | ||||
|             consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, | ||||
|             produces = MediaType.APPLICATION_JSON_UTF8_VALUE) | ||||
|     public Configuration undo(@PathVariable final String modelId) { | ||||
| 
 | ||||
|         return this.entityDAO.byModelId(modelId) | ||||
|                 .flatMap(this::checkModifyAccess) | ||||
|                 .flatMap(config -> this.configurationDAO.undo(config.configurationNodeId)) | ||||
|                 .getOrThrow(); | ||||
|     } | ||||
| 
 | ||||
|     @RequestMapping( | ||||
|             path = API.CONFIGURATION_RESTORE_FROM_HISTORY_PATH_SEGMENT + API.MODEL_ID_VAR_PATH_SEGMENT, | ||||
|             method = RequestMethod.POST, | ||||
|             consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE, | ||||
|             produces = MediaType.APPLICATION_JSON_UTF8_VALUE) | ||||
|     public Configuration restoreFormHistory( | ||||
|             @PathVariable final String configId, | ||||
|             @PathVariable final String modelId, | ||||
|             @RequestParam(name = API.PARAM_PARENT_MODEL_ID, required = true) final Long configurationNodeId) { | ||||
| 
 | ||||
|         return this.entityDAO.byModelId(configId) | ||||
|         return this.entityDAO.byModelId(modelId) | ||||
|                 .flatMap(this::checkModifyAccess) | ||||
|                 .flatMap(config -> this.configurationDAO.restoreToVersion(configurationNodeId, config.getId())) | ||||
|                 .getOrThrow(); | ||||
|  |  | |||
|  | @ -360,6 +360,10 @@ sebserver.examconfig.action.list.modify.properties=Edit Properties | |||
| sebserver.examconfig.action.modify=Edit | ||||
| sebserver.examconfig.action.modify.properties=Edit Properties | ||||
| sebserver.examconfig.action.save=Save | ||||
| sebserver.examconfig.action.saveToHistory=Save In History | ||||
| sebserver.examconfig.action.saveToHistory.success=Successfully saved in history | ||||
| sebserver.examconfig.action.undo=Undo | ||||
| sebserver.examconfig.action.undo.success=Successfully reverted to last saved state | ||||
| 
 | ||||
| sebserver.examconfig.form.title.new=New Exam Configuration | ||||
| sebserver.examconfig.form.title=Exam Configuration | ||||
|  | @ -378,6 +382,11 @@ sebserver.examconfig.props.form.views.browser=Browser | |||
| sebserver.examconfig.props.form.views.down_upload=Down/Uploads | ||||
| sebserver.examconfig.props.form.views.exam=Exam | ||||
| sebserver.examconfig.props.form.views.applications=Applications | ||||
| sebserver.examconfig.props.form.views.resources=Additional Resources | ||||
| sebserver.examconfig.props.form.views.network=Network | ||||
| sebserver.examconfig.props.form.views.security=Security | ||||
| sebserver.examconfig.props.form.views.registry=Registry | ||||
| sebserver.examconfig.props.form.views.hooked_keys=Hooked Keys | ||||
| 
 | ||||
| sebserver.examconfig.props.label.hashedAdminPassword=Administrator password | ||||
| sebserver.examconfig.props.label.hashedAdminPassword.confirm=Confirm password | ||||
|  | @ -570,6 +579,122 @@ sebserver.examconfig.props.label.prohibitedProcesses.originalName=Original Name | |||
| sebserver.examconfig.props.label.prohibitedProcesses.identifier=Identifier | ||||
| sebserver.examconfig.props.label.prohibitedProcesses.strongKill=Force quit (risk of data loss) | ||||
| 
 | ||||
| sebserver.examconfig.props.label.URLFilterEnable=Activate URL Filtering | ||||
| sebserver.examconfig.props.label.URLFilterEnableContentFilter=Filter also embedded content | ||||
| sebserver.examconfig.props.label.URLFilterRules=Filter | ||||
| sebserver.examconfig.props.label.URLFilterRules.active=Activity | ||||
| sebserver.examconfig.props.label.URLFilterRules.regex=Regex | ||||
| sebserver.examconfig.props.label.URLFilterRules.expression=Expression | ||||
| sebserver.examconfig.props.label.URLFilterRules.action=Action | ||||
| sebserver.examconfig.props.label.URLFilterRules.action.0=Block | ||||
| sebserver.examconfig.props.label.URLFilterRules.action.1=Allow | ||||
| 
 | ||||
| sebserver.examconfig.props.group.servicePolicy=SEB Service policy | ||||
| sebserver.examconfig.props.label.sebServicePolicy.0=allow to run SEB without service | ||||
| sebserver.examconfig.props.label.sebServicePolicy.1=display warning when service is not running | ||||
| sebserver.examconfig.props.label.sebServicePolicy.2=allow to use SEB only with service | ||||
| sebserver.examconfig.props.label.sebServicePolicy.tooltip=Policy that applies when an exam client doesn't have the SEB client running | ||||
| 
 | ||||
| sebserver.examconfig.props.group.kioskMode=Kiosk Mode | ||||
| sebserver.examconfig.props.label.kioskMode.tooltip=The kiosk mode setting reflects how the computer is locked down into SEB. | ||||
| sebserver.examconfig.props.label.kioskMode.0=Create new desktop | ||||
| sebserver.examconfig.props.label.kioskMode.0.tooltip=This kiosk mode may prevent specific third party software to run correctly together with SEB, like some screen recording software or the Windows onscreen keyboard. | ||||
| sebserver.examconfig.props.label.kioskMode.1=Disable explorer Shell | ||||
| sebserver.examconfig.props.label.kioskMode.1.tooltip=This kiosk mode is compatible with some screen recording/proctoring software and the Windows onscreen keyboard. | ||||
| sebserver.examconfig.props.label.kioskMode.2=None (for debugging only) | ||||
| sebserver.examconfig.props.label.kioskMode.2.tooltip=SEB runs without kiosk mode, switching to other applications is possible. Use this for debugging purposes only. | ||||
| 
 | ||||
| sebserver.examconfig.props.label.allowVirtualMachine=Allow to run inside virtual machine | ||||
| sebserver.examconfig.props.label.allowVirtualMachine.tooltip=Indicates if SEB is allowed to run in a virtual machine or not (in order to prevent potential manipulation). | ||||
| sebserver.examconfig.props.label.allowScreenSharing=Allow remote session/screen sharing | ||||
| sebserver.examconfig.props.label.allowScreenSharing.tootlip=Allows Windows remote sessions and macOS screen sharing to be used | ||||
| sebserver.examconfig.props.label.enablePrivateClipboard=Use private clipboard (Mac) | ||||
| sebserver.examconfig.props.label.enablePrivateClipboard.tooltip=Private clipboard should always be used beside when working with third party application in managed/virtual machine | ||||
| 
 | ||||
| sebserver.examconfig.props.group.logging=Logging | ||||
| sebserver.examconfig.props.label.enableLogging=Enable logging | ||||
| sebserver.examconfig.props.label.enableLogging.tooltip=The log can help debugging SEB (send it to the developers) and to find out about possible manipulations | ||||
| sebserver.examconfig.props.label.logDirectoryWin=Log file directory on Windows | ||||
| sebserver.examconfig.props.label.logDirectoryOSX=Log file directory on Mac | ||||
| 
 | ||||
| sebserver.examconfig.props.group.macSettings=macOS specific settings | ||||
| sebserver.examconfig.props.label.minMacOSVersion=Enforce minimal macOS version: | ||||
| sebserver.examconfig.props.label.minMacOSVersion.0=OS X 10.7 Lion | ||||
| sebserver.examconfig.props.label.minMacOSVersion.1=OS X 10.8 Mountain Lion | ||||
| sebserver.examconfig.props.label.minMacOSVersion.2=OS X 10.9 Mavericks | ||||
| sebserver.examconfig.props.label.minMacOSVersion.3=OS X 10.10 Yosemite | ||||
| sebserver.examconfig.props.label.minMacOSVersion.4=OS X 10.11 El Capitan | ||||
| sebserver.examconfig.props.label.minMacOSVersion.5=OS X 10.12 Sierra | ||||
| sebserver.examconfig.props.label.minMacOSVersion.6=OS X 10.13 Hight Sierra | ||||
| sebserver.examconfig.props.label.minMacOSVersion.7=OS X 10.14 Mojave | ||||
| sebserver.examconfig.props.label.enableAppSwitcherCheck=Disable app switcher when starting | ||||
| sebserver.examconfig.props.label.enableAppSwitcherCheck.tooltip=SEB checks for the command key being held down while SEB is starting up. This prevents using the application switcher to mess with SEB\'s kiosk mode | ||||
| sebserver.examconfig.props.label.forceAppFolderInstall=Force installation in Applications folder | ||||
| sebserver.examconfig.props.label.forceAppFolderInstall.tooltip=SEB enforces to be installed in an Applications folder (/Applications or ~/Applications) | ||||
| sebserver.examconfig.props.label.allowUserAppFolderInstall=Allow also user's ~/Applications folder | ||||
| sebserver.examconfig.props.label.allowUserAppFolderInstall.tooltip=SEB can also be installed in the Applications folder of the current user (~/Applications) | ||||
| sebserver.examconfig.props.label.allowSiri=Allow to use Siri | ||||
| sebserver.examconfig.props.label.allowSiri.tooltip=If enabled, Siri can be used by tapping th emenu bar icon, Touch Bar icon or shortcut set in System Preferences/Siri (default: hold command space). The Siri window won't be displayed though  | ||||
| sebserver.examconfig.props.label.detectStoppedProcess=Detect when SEB process was stopped | ||||
| sebserver.examconfig.props.label.detectStoppedProcess.tooltip=SEB displays a lock screen (requiring to enter the quit/unlock password) if it detects its process was stopped, which can indicate manipulation | ||||
| sebserver.examconfig.props.label.allowDisplayMirroring=Allow display mirroring (affects also AirPlay Display) | ||||
| sebserver.examconfig.props.label.allowDisplayMirroring.tooltip=If not selected, SEB prevents to mirror the main display to another | ||||
| sebserver.examconfig.props.label.allowedDisplaysMaxNumber=Maximum allowed number of connected displays | ||||
| sebserver.examconfig.props.label.allowedDisplaysMaxNumber.tooltip=If more displays are connected, this are blanked with an orange full screen window | ||||
| sebserver.examconfig.props.label.allowedDisplayBuiltin=Use built-in display | ||||
| sebserver.examconfig.props.label.allowedDisplayBuiltin.tooltip=Use the built-in display (if available) when only one display is allowed or when switching off display mirroring | ||||
| 
 | ||||
| sebserver.examconfig.props.group.registry=While running SEB | ||||
| sebserver.examconfig.props.group.registry.tooltip=Options in the Windows Security Screen invoked by Ctrl-Alt-Del | ||||
| sebserver.examconfig.props.label.insideSebEnableSwitchUser=Enable Switch User | ||||
| sebserver.examconfig.props.label.insideSebEnableSwitchUser.tooltip=Activates the button "Switch User" | ||||
| sebserver.examconfig.props.label.insideSebEnableLockThisComputer=Enable Lock this computer | ||||
| sebserver.examconfig.props.label.insideSebEnableLockThisComputer.tooltip=Activates the button "Lock this computer" | ||||
| sebserver.examconfig.props.label.insideSebEnableChangeAPassword=Enable Change a password | ||||
| sebserver.examconfig.props.label.insideSebEnableChangeAPassword.tooltip=Activates the button "Change a password..." | ||||
| sebserver.examconfig.props.label.insideSebEnableStartTaskManager=Enable Start Task Manager | ||||
| sebserver.examconfig.props.label.insideSebEnableStartTaskManager.tooltip=Activates the button "Start Task Manager" | ||||
| sebserver.examconfig.props.label.insideSebEnableLogOff=Enable Log off | ||||
| sebserver.examconfig.props.label.insideSebEnableLogOff.tooltip=Activates the button "Log off" | ||||
| sebserver.examconfig.props.label.insideSebEnableShutDown=Enable Shut down | ||||
| sebserver.examconfig.props.label.insideSebEnableShutDown.tooltip=Activates the button "Shutdown" | ||||
| sebserver.examconfig.props.label.insideSebEnableEaseOfAccess=Enable Ease of Access | ||||
| sebserver.examconfig.props.label.insideSebEnableEaseOfAccess.tooltip=Shows options when the button "Ease of Access" in the lower left corner is clicked,\nwhich offers help e.g. to visually or aurally handicapped persons, like the Magnifier Glass. | ||||
| sebserver.examconfig.props.label.insideSebEnableVmWareClientShade=Enable VMware Client Shade | ||||
| sebserver.examconfig.props.label.insideSebEnableVmWareClientShade.tooltip=Activates the "Shade" bar at the upper edge of a virtual desktop, if existent. If you're not using VMware, this setting doesn't have any effect. | ||||
| sebserver.examconfig.props.label.insideSebEnableNetworkConnectionSelector=Enable network connection selector | ||||
| sebserver.examconfig.props.label.insideSebEnableNetworkConnectionSelector.tooltip=Activates the button which allows to connect to WiFi networks, introduces in Windows 10. | ||||
| 
 | ||||
| sebserver.examconfig.props.group.specialKeys=Special Keys | ||||
| sebserver.examconfig.props.group.specialKeys.tooltip=Settings to enable or block (hook) keys, key combinations and mouse buttons.  | ||||
| sebserver.examconfig.props.label.enableEsc=Enable Esc | ||||
| sebserver.examconfig.props.label.enablePrintScreen=Enable Print Screen | ||||
| sebserver.examconfig.props.label.enablePrintScreen.tooltip=Controls Print Screen and OS X screen capture, corresponds with Enable screen capture in Security settings. | ||||
| sebserver.examconfig.props.label.enableCtrlEsc=Enable Ctrl-Esc | ||||
| sebserver.examconfig.props.label.enableAltEsc=Enable Alt-Esc | ||||
| sebserver.examconfig.props.label.enableAltTab=Enable Alt-Tap | ||||
| sebserver.examconfig.props.label.enableAltF4=Enable Alt-F4  | ||||
| sebserver.examconfig.props.label.enableStartMenu=Enable Start Menu | ||||
| sebserver.examconfig.props.label.enableRightMouse=Enable Right Mouse | ||||
| sebserver.examconfig.props.label.enableAltMouseWheel=Enable Alt-Mousewheel | ||||
| sebserver.examconfig.props.label.enableAltMouseWheel.tooltip=Corresponds to 'Allow browsing back/forward' in Browser pane. Disabling browsing to previously visited pages may increase security, because browsing back might allow to leave an exam | ||||
| 
 | ||||
| sebserver.examconfig.props.group.functionKeys=Function Keys | ||||
| sebserver.examconfig.props.group.functionKeys.tooltip=Enable or block function keys. This doesn't have any effect on the SEB exit sequence. Depending on specific keyboards some function keys cannot be blocked. | ||||
| sebserver.examconfig.props.label.enableF1=Enable F1 | ||||
| sebserver.examconfig.props.label.enableF2=Enable F2 | ||||
| sebserver.examconfig.props.label.enableF3=Enable F3 | ||||
| sebserver.examconfig.props.label.enableF4=Enable F4 | ||||
| sebserver.examconfig.props.label.enableF5=Enable F5 | ||||
| sebserver.examconfig.props.label.enableF6=Enable F6 | ||||
| sebserver.examconfig.props.label.enableF7=Enable F7 | ||||
| sebserver.examconfig.props.label.enableF8=Enable F8 | ||||
| sebserver.examconfig.props.label.enableF9=Enable F9 | ||||
| sebserver.examconfig.props.label.enableF10=Enable F10 | ||||
| sebserver.examconfig.props.label.enableF11=Enable F11 | ||||
| sebserver.examconfig.props.label.enableF12=Enable F12 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| sebserver.examconfig.props.validation.password.confirm=Please enter correct confirm password | ||||
| sebserver.examconfig.props.validation.unexpected=Unexpected error happened. Value was not set correctly | ||||
|  |  | |||
|  | @ -604,7 +604,7 @@ TabItem { | |||
|   text-decoration: none; | ||||
|   text-shadow: none; | ||||
|   background-image: none; | ||||
|   margin: 1px 0px 0px -1px; | ||||
|   margin: 1px 0px 0px 0px; | ||||
|   border: 1px solid #bdbdbd; | ||||
|   border-bottom: none; | ||||
|   border-left: none; | ||||
|  | @ -734,15 +734,6 @@ Widget-ToolTip-Pointer { | |||
|     background-image: none; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* Table default theme */ | ||||
| Table { | ||||
|     font: 12px Arial, Helvetica, sans-serif; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 anhefti
						anhefti