SEBSERV-33 fix and improvements

This commit is contained in:
anhefti 2020-01-22 16:44:25 +01:00
parent 77aae3ad54
commit ed8387216b
26 changed files with 86 additions and 106 deletions

View file

@ -135,8 +135,7 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
final boolean hasView = attribute.getOrientation() != null;
this.pageService.formBuilder(
formContext, 4)
this.pageService.formBuilder(formContext)
.readonly(true) // TODO change this for next version
.addField(FormBuilder.text(
Domain.CONFIGURATION_ATTRIBUTE.ATTR_NAME,
@ -161,12 +160,18 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
attribute.getGroupId()))
.build();
final Composite valSpace = new Composite(content, SWT.NONE);
valSpace.setLayout(new GridLayout());
valSpace.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
widgetFactory.labelLocalized(
content,
valSpace,
CustomVariant.TEXT_H2,
FORM_VALUE_TEXT_KEY);
final Composite grid = new Composite(content, SWT.NONE);
widgetFactory.labelSeparator(valSpace);
final Composite grid = new Composite(valSpace, SWT.NONE);
grid.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
grid.setLayout(new GridLayout(6, true));
@ -188,7 +193,7 @@ public class ConfigTemplateAttributeForm implements TemplateComposer {
defaultOrientation);
final InputField createInputField = inputFieldBuilder.createInputField(
content,
grid,
attribute.getConfigAttribute(),
viewContext);

View file

@ -141,7 +141,7 @@ public class ConfigTemplateForm implements TemplateComposer {
// The SebClientConfig form
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
formContext.copyOf(content))
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.CONFIGURATION_NODE.ATTR_ID,

View file

@ -42,7 +42,6 @@ import ch.ethz.seb.sebserver.gbl.model.exam.ExamConfigurationMap;
import ch.ethz.seb.sebserver.gbl.model.exam.Indicator;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup.Features;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
import ch.ethz.seb.sebserver.gbl.util.Result;
@ -71,7 +70,6 @@ import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetExamConfi
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.GetIndicatorPage;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.exam.SaveExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.GetLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.lmssetup.TestLmsSetup;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.GetQuizData;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.api.quiz.ImportAsExam;
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.CurrentUser;
@ -379,6 +377,7 @@ public class ExamForm implements TemplateComposer {
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(exam.lmsSetupId))
.call()
.getOrThrow().lmsType.name())
.noEventPropagation()
.publishIf(() -> sebRestrictionAvailable && readonly)
.newAction(ActionDefinition.EXAM_ENABLE_SEB_RESTRICTION)
@ -394,13 +393,13 @@ public class ExamForm implements TemplateComposer {
// additional data in read-only view
if (readonly && !importFromQuizData) {
this.widgetFactory.labelSeparator(content);
// List of SEB Configuration
this.widgetFactory.label(content, "");
this.widgetFactory.labelLocalized(
content,
CustomVariant.TEXT_H3,
CONFIG_LIST_TITLE_KEY);
this.widgetFactory.labelSeparator(content);
final EntityTable<ExamConfigurationMap> configurationTable =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigMappingsPage.class))
@ -481,13 +480,13 @@ public class ExamForm implements TemplateComposer {
.noEventPropagation()
.publishIf(() -> userGrantCheck.r() && configurationTable.hasAnyContent());
this.widgetFactory.labelSeparator(content);
// List of Indicators
this.widgetFactory.label(content, "");
this.widgetFactory.labelLocalized(
content,
CustomVariant.TEXT_H3,
INDICATOR_LIST_TITLE_KEY);
this.widgetFactory.labelSeparator(content);
final EntityTable<Indicator> indicatorTable =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetIndicatorPage.class))
@ -568,19 +567,12 @@ public class ExamForm implements TemplateComposer {
}
private boolean testSebRestrictionAPI(final Exam exam) {
final boolean hasFeature = this.restService.getBuilder(GetLmsSetup.class)
return this.restService.getBuilder(GetLmsSetup.class)
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(exam.lmsSetupId))
.call()
.onError(t -> log.error("Failed to check SEB restriction API: ", t))
.map(lmsSetup -> lmsSetup.lmsType.features.contains(Features.SEB_RESTICTION))
.getOr(false);
return hasFeature && this.restService.getBuilder(TestLmsSetup.class)
.withURIVariable(API.PARAM_MODEL_ID, String.valueOf(exam.lmsSetupId))
.call()
.onError(t -> log.error("Failed to check SEB restriction API: ", t))
.map(result -> !result.hasError(LmsSetupTestResult.ErrorType.QUIZ_RESTRICTION_API_REQUEST))
.getOr(false);
}
private void showConsistencyChecks(final Collection<APIMessage> result, final Composite parent) {

View file

@ -182,8 +182,8 @@ public class ExamSebRestrictionSettings {
.clearEntityKeys();
final FormHandle<SebRestriction> formHandle = this.pageService.formBuilder(
formContext, 3)
.withDefaultSpanEmptyCell(0)
formContext)
.withDefaultSpanInput(6)
.withEmptyCellSeparation(false)
.readonly(false)

View file

@ -159,6 +159,10 @@ final class ExamToConfigBindingForm {
@Override
public Supplier<FormHandle<ExamConfigurationMap>> compose(final Composite parent) {
final Composite grid = this.pageService.getWidgetFactory()
.createPopupScrollComposite(parent);
final RestService restService = this.pageService.getRestService();
final ResourceService resourceService = this.pageService.getResourceService();
@ -191,7 +195,7 @@ final class ExamToConfigBindingForm {
final PageContext formContext = this.pageContext.withEntityKey(examConfigurationMap.getEntityKey());
final FormHandle<ExamConfigurationMap> formHandle = this.pageService.formBuilder(
formContext.copyOf(parent), 4)
formContext.copyOf(grid))
.readonly(false)
.putStaticValueIf(() -> !isNew,
Domain.EXAM_CONFIGURATION_MAP.ATTR_ID,

View file

@ -122,7 +122,7 @@ public class IndicatorForm implements TemplateComposer {
titleKey);
final FormHandle<Indicator> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
formContext.copyOf(content))
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.INDICATOR.ATTR_ID,
@ -156,7 +156,7 @@ public class IndicatorForm implements TemplateComposer {
typeDescription)
.asArea()
.readonly(true)
.withInputSpan(3))
.withInputSpan(6))
.addField(FormBuilder.colorSelection(
Domain.INDICATOR.ATTR_COLOR,

View file

@ -102,7 +102,7 @@ public class InstitutionForm implements TemplateComposer {
// The Institution form
final FormHandle<Institution> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
formContext.copyOf(content))
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.INSTITUTION.ATTR_ID,

View file

@ -148,8 +148,8 @@ public class LmsSetupForm implements TemplateComposer {
final FormHandle<LmsSetup> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 8)
.withDefaultSpanLabel(2)
.withDefaultSpanInput(4)
.withDefaultSpanEmptyCell(2)
.withDefaultSpanInput(5)
.withDefaultSpanEmptyCell(1)
.readonly(readonly)
.putStaticValueIf(isNotNew,
Domain.LMS_SETUP.ATTR_ID,
@ -208,7 +208,7 @@ public class LmsSetupForm implements TemplateComposer {
Domain.LMS_SETUP.ATTR_LMS_PROXY_HOST,
FORM_PROXY_HOST_KEY,
(StringUtils.isNotBlank(lmsSetup.getProxyHost())) ? lmsSetup.getProxyHost() : null)
.withInputSpan(2)
.withInputSpan(3)
.withEmptyCellSpan(0))
.addFieldIf(
isEdit,
@ -231,7 +231,7 @@ public class LmsSetupForm implements TemplateComposer {
Domain.LMS_SETUP.ATTR_LMS_PROXY_AUTH_USERNAME,
FORM_PROXY_AUTH_CREDENTIALS_KEY,
(lmsSetup.getProxyAuthUsername() != null) ? lmsSetup.getProxyAuthUsername() : null)
.withInputSpan(2)
.withInputSpan(3)
.withEmptyCellSpan(0))
.addFieldIf(
isEdit,

View file

@ -286,7 +286,8 @@ public class QuizDiscoveryList implements TemplateComposer {
final Composite parent = pc.getParent();
final Composite grid = this.widgetFactory.createPopupScrollComposite(parent);
final FormBuilder formbuilder = this.pageService.formBuilder(pc.copyOf(grid), 3)
final FormBuilder formbuilder = this.pageService.formBuilder(pc.copyOf(grid))
.withDefaultSpanInput(6)
.withEmptyCellSeparation(false)
.readonly(true)
.addFieldIf(

View file

@ -123,7 +123,7 @@ public class SebClientConfigForm implements TemplateComposer {
// The SebClientConfig form
final FormHandle<SebClientConfig> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
formContext.copyOf(content))
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.SEB_CLIENT_CONFIGURATION.ATTR_ID,

View file

@ -261,7 +261,8 @@ public class SebClientLogs implements TemplateComposer {
CustomVariant.TEXT_H3,
DETAILS_EVENT_TILE_TEXT_KEY);
this.pageService.formBuilder(pc.copyOf(content), 3)
this.pageService.formBuilder(pc.copyOf(content))
.withDefaultSpanInput(6)
.withEmptyCellSeparation(false)
.readonly(true)
.addField(FormBuilder.text(
@ -302,7 +303,8 @@ public class SebClientLogs implements TemplateComposer {
error -> log.error("Failed to get ClientConnection for id {}", clientEvent.connectionId, error),
() -> ClientConnection.EMPTY_CLIENT_CONNECTION);
this.pageService.formBuilder(pc.copyOf(content), 3)
this.pageService.formBuilder(pc.copyOf(content))
.withDefaultSpanInput(6)
.withEmptyCellSeparation(false)
.readonly(true)
.addField(FormBuilder.text(
@ -336,7 +338,8 @@ public class SebClientLogs implements TemplateComposer {
error -> log.error("Failed to get Exam for id {}", clientEvent.examId, error),
() -> Exam.EMPTY_EXAM);
this.pageService.formBuilder(pc.copyOf(content), 3)
this.pageService.formBuilder(pc.copyOf(content))
.withDefaultSpanInput(6)
.withEmptyCellSeparation(false)
.readonly(true)
.addField(FormBuilder.text(

View file

@ -152,9 +152,12 @@ final class SebExamConfigCreationPopup {
@Override
public Supplier<FormHandle<ConfigCreationInfo>> compose(final Composite parent) {
final Composite grid = this.pageService.getWidgetFactory()
.createPopupScrollComposite(parent);
final EntityKey entityKey = this.pageContext.getEntityKey();
final FormHandle<ConfigCreationInfo> formHandle = this.pageService.formBuilder(
this.pageContext.copyOf(parent), 4)
this.pageContext.copyOf(grid))
.readonly(false)
.putStaticValueIf(
() -> !this.createFromTemplate,

View file

@ -225,10 +225,13 @@ final class SebExamConfigImportPopup {
@Override
public Supplier<FormHandle<ConfigurationNode>> compose(final Composite parent) {
final Composite grid = this.pageService.getWidgetFactory()
.createPopupScrollComposite(parent);
final ResourceService resourceService = this.pageService.getResourceService();
final List<Tuple<String>> examConfigTemplateResources = resourceService.getExamConfigTemplateResources();
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
this.pageContext.copyOf(parent), 4)
this.pageContext.copyOf(grid))
.readonly(false)
.addField(FormBuilder.fileUpload(
API.IMPORT_FILE_ATTR_NAME,

View file

@ -149,10 +149,10 @@ public class SebExamConfigList implements TemplateComposer {
// configuration template table
widgetFactory.label(content, "");
widgetFactory.labelSeparator(content);
widgetFactory.labelLocalizedTitle(
content,
TITLE_TEMPLATE_TEXT_KEY);
widgetFactory.labelSeparator(content);
final EntityTable<ConfigurationNode> templateTable =
this.pageService.entityTableBuilder(this.restService.getRestCall(GetExamConfigNodePage.class))

View file

@ -162,7 +162,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
final List<Tuple<String>> examConfigTemplateResources = resourceService.getExamConfigTemplateResources();
final FormHandle<ConfigurationNode> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
formContext.copyOf(content))
.readonly(isReadonly)
.putStaticValueIf(() -> !isNew,
Domain.CONFIGURATION_NODE.ATTR_ID,
@ -191,8 +191,7 @@ public class SebExamConfigPropForm implements TemplateComposer {
Domain.CONFIGURATION_NODE.ATTR_DESCRIPTION,
FORM_DESCRIPTION_TEXT_KEY,
examConfig.description)
.asArea()
.withInputSpan((isReadonly) ? 3 : 2))
.asArea())
.addField(FormBuilder.singleSelection(
Domain.CONFIGURATION_NODE.ATTR_STATUS,

View file

@ -91,8 +91,7 @@ public class UserAccountChangePasswordForm implements TemplateComposer {
final boolean ownAccount = this.currentUser.get().uuid.equals(entityKey.getModelId());
// The Password Change form
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(
pageContext.copyOf(content), 4)
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(pageContext.copyOf(content))
.readonly(false)
.putStaticValueIf(() -> entityKey != null,
Domain.USER.ATTR_UUID,

View file

@ -141,7 +141,7 @@ public class UserAccountForm implements TemplateComposer {
// The UserAccount form
final FormHandle<UserInfo> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
formContext.copyOf(content))
.readonly(readonly)
.putStaticValueIf(isNotNew,
Domain.USER.ATTR_UUID,

View file

@ -223,8 +223,7 @@ public class UserActivityLogs implements TemplateComposer {
final ModalInputDialog<Void> dialog = new ModalInputDialog<>(
action.pageContext().getParent().getShell(),
this.widgetFactory);
//dialog.setDialogHeight(400);
dialog.setLargeDialogWidth();
dialog.open(
DETAILS_TITLE_TEXT_KEY,
action.pageContext(),
@ -238,7 +237,8 @@ public class UserActivityLogs implements TemplateComposer {
final Composite parent = pc.getParent();
final Composite grid = this.widgetFactory.createPopupScrollComposite(parent);
this.pageService.formBuilder(pc.copyOf(grid), 3)
this.pageService.formBuilder(pc.copyOf(grid))
.withDefaultSpanInput(6)
.withEmptyCellSeparation(false)
.readonly(true)
.addField(FormBuilder.text(

View file

@ -48,8 +48,8 @@ public class FormBuilder {
public final Form form;
boolean readonly = false;
private int defaultSpanLabel = 1;
private int defaultSpanInput = 2;
private int defaultSpanLabel = 2;
private int defaultSpanInput = 5;
private int defaultSpanEmptyCell = 1;
private boolean emptyCellSeparation = true;
@ -188,8 +188,10 @@ public class FormBuilder {
private void empty(final Composite parent, final int hspan, final int vspan) {
final Label empty = new Label(parent, SWT.LEFT);
empty.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, hspan, vspan));
empty.setText("");
final GridData gridData = new GridData(SWT.LEFT, SWT.TOP, false, false, hspan, vspan);
gridData.minimumWidth = 0;
gridData.widthHint = 0;
empty.setLayoutData(gridData);
}
public static CheckboxFieldBuilder checkbox(final String name, final LocTextKey label) {

View file

@ -104,9 +104,11 @@ public final class SelectionFieldBuilder extends FieldBuilder<String> {
gridLayout.marginHeight = 0;
gridLayout.marginWidth = 0;
composite.setLayout(gridLayout);
composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, this.spanInput, 1));
if (StringUtils.isBlank(this.value)) {
final Label label = new Label(composite, SWT.NONE);
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
label.setLayoutData(gridData);
label.setText(this.value);
} else {
@ -115,7 +117,7 @@ public final class SelectionFieldBuilder extends FieldBuilder<String> {
.stream()
.filter(tuple -> keys.contains(tuple._1))
.map(tuple -> tuple._1)
.forEach(v -> buildReadonlyLabel(composite, v, 0));
.forEach(v -> buildReadonlyLabel(composite, v, 1));
}
} else {
builder.form.putReadonlyField(
@ -128,7 +130,7 @@ public final class SelectionFieldBuilder extends FieldBuilder<String> {
private Text buildReadonlyLabel(final Composite composite, final String valueKey, final int hspan) {
final Text label = new Text(composite, SWT.READ_ONLY);
final GridData gridData = new GridData(SWT.LEFT, SWT.TOP, true, true, hspan, 1);
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true, hspan, 1);
gridData.verticalIndent = 0;
gridData.horizontalIndent = 0;
label.setLayoutData(gridData);

View file

@ -95,7 +95,7 @@ public final class TextFieldBuilder extends FieldBuilder<String> {
final Browser browser = new Browser(fieldGrid, SWT.NONE);
final GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, true);
gridData.minimumHeight = this.areaMinHeight;
browser.setBackground(new Color(builder.formParent.getDisplay(), new RGB(240, 240, 240)));
browser.setBackground(new Color(builder.formParent.getDisplay(), new RGB(250, 250, 250)));
browser.setLayoutData(gridData);
if (StringUtils.isNoneBlank(this.value)) {
browser.setText(createHTMLText(this.value));

View file

@ -181,6 +181,15 @@ public interface PageService {
* @param pageAction the PageAction to publish */
void publishAction(final PageAction pageAction);
/** Get a new FormBuilder for the given PageContext
* This FormBuilder uses the standard form grid which has 8 rows (2 title, 5 input and 1 right-space)
*
* @param pageContext the PageContext on that the FormBuilder should work
* @return a FormBuilder instance for the given PageContext and with number of rows */
default FormBuilder formBuilder(final PageContext pageContext) {
return formBuilder(pageContext, 8);
}
/** Get a new FormBuilder for the given PageContext and with number of rows.
*
* @param pageContext the PageContext on that the FormBuilder should work

View file

@ -297,9 +297,15 @@ public class PageServiceImpl implements PageService {
.getUISession()
.getHttpSession();
if (action != null && action.definition != null && action.definition.targetState != null) {
if (action != null &&
action.fireActionEvent &&
action.definition != null &&
action.definition.targetState != null) {
final PageState pageState = new PageState(action.definition.targetState, action);
log.debug("Set session PageState: {} : {}", pageState, httpSession.getId());
if (log.isDebugEnabled()) {
log.debug("Set session PageState: {} : {}", pageState, httpSession.getId());
}
httpSession.setAttribute(ATTR_PAGE_STATE, pageState);
}
} catch (final Exception e) {

View file

@ -81,7 +81,7 @@ public class ClientConnectionDetails {
this.colorData,
NUMBER_OF_NONE_INDICATOR_ROWS);
final FormBuilder formBuilder = this.pageService.formBuilder(pageContext, 4)
final FormBuilder formBuilder = this.pageService.formBuilder(pageContext)
.readonly(true)
.addField(FormBuilder.text(
QuizData.QUIZ_ATTR_NAME,
@ -95,7 +95,7 @@ public class ClientConnectionDetails {
Domain.CLIENT_CONNECTION.ATTR_CLIENT_ADDRESS,
CONNECTION_ADDRESS_TEXT_KEY,
Constants.EMPTY_NOTE))
.withDefaultSpanInput(1)
.withDefaultSpanInput(3)
.addField(FormBuilder.text(
Domain.CLIENT_CONNECTION.ATTR_STATUS,
CONNECTION_STATUS_TEXT_KEY,

View file

@ -196,11 +196,6 @@ public class FileUploadSelection extends Composite {
}
void close() {
try {
this.pOut.flush();
} catch (final Exception e) {
log.error("Unexpected error while trying to flush: ", e);
}
IOUtils.closeQuietly(this.pOut);
}
}

View file

@ -102,49 +102,6 @@ final class OpenEdxCourseAccess extends CourseAccess {
return LmsSetupTestResult.ofOkay();
}
//
// Result<QuizData> getQuizFromCache(final String id) {
// return Result.tryCatch(() -> {
// return this.allQuizzesSupplier
// .getChached()
// .stream()
// .filter(qd -> id.equals(qd.id))
// .findFirst()
// .orElseThrow(() -> new NoSuchElementException("No cached quiz: " + id));
// });
// }
//
// Result<Collection<Result<QuizData>>> getQuizzesFromCache(final Set<String> ids) {
// return Result.tryCatch(() -> {
// final List<QuizData> cached = this.allQuizzesSupplier.getChached();
// if (cached == null) {
// throw new RuntimeException("No cached quizzes");
// }
//
// final Map<String, QuizData> cacheMapping = cached
// .stream()
// .collect(Collectors.toMap(q -> q.id, Function.identity()));
//
// if (!cacheMapping.keySet().containsAll(ids)) {
// throw new RuntimeException("Not all requested quizzes cached");
// }
//
// return ids
// .stream()
// .map(id -> {
// final QuizData q = cacheMapping.get(id);
// return (q == null)
// ? Result.<QuizData> ofError(new NoSuchElementException("Quiz with id: " + id))
// : Result.of(q);
// })
// .collect(Collectors.toList());
// });
// }
// Result<List<QuizData>> getQuizzes(final FilterMap filterMap) {
// return this.allQuizzesSupplier.get()
// .map(LmsAPIService.quizzesFilterFunction(filterMap));
// }
@Override
protected Supplier<List<QuizData>> allQuizzesSupplier() {