diff --git a/backend/pepper-parent/pom.xml b/backend/pepper-parent/pom.xml index e901846..d6046e5 100644 --- a/backend/pepper-parent/pom.xml +++ b/backend/pepper-parent/pom.xml @@ -63,12 +63,12 @@ pepper-mm pepper-mm - 2026.3.0 + 2026.4.0 pepper-mm pepper-edit - 2026.3.0 + 2026.4.0 diff --git a/backend/pepper-starter/src/main/java/pepper/starter/messages/MessageConstants.java b/backend/pepper-starter/src/main/java/pepper/starter/messages/MessageConstants.java index 88c5d2d..5f8cadb 100644 --- a/backend/pepper-starter/src/main/java/pepper/starter/messages/MessageConstants.java +++ b/backend/pepper-starter/src/main/java/pepper/starter/messages/MessageConstants.java @@ -50,6 +50,20 @@ public final class MessageConstants { public static final String PAGE_RISKS_TITLE = "PAGE_RISKS_TITLE"; + public static final String RESOURCE_FORM_TITLE = "RESOURCE_FORM_TITLE"; + + public static final String PAGE_RESOURCE_AVAILABILITY = "PAGE_RESOURCE_AVAILABILITY"; + + public static final String PAGE_RESOURCE_AVAILABILITY_TITLE = "PAGE_RESOURCE_AVAILABILITY_TITLE"; + + public static final String UNAVAILABILITY_PERIOD_FORM_TITLE = "UNAVAILABILITY_PERIOD_FORM_TITLE"; + + public static final String CREATE_NEW_UNAVAILABILITY_PERIOD = "CREATE_NEW_UNAVAILABILITY_PERIOD"; + + public static final String CREATE_NEW_UNAVAILABILITY_PERIOD_HELP = "CREATE_NEW_UNAVAILABILITY_PERIOD_HELP"; + + public static final String DELETE_UNAVAILABILITY_PERIOD = "DELETE_UNAVAILABILITY_PERIOD"; + public static final String INVALID_INPUT = "INVALID_INPUT"; public static final String CREATE_NEW_WORKPACKAGE = "CREATE_NEW_WORKPACKAGE"; diff --git a/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/PepperMMEditingContextDescriptionProvider.java b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/PepperMMEditingContextDescriptionProvider.java index 2470968..c0699ad 100644 --- a/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/PepperMMEditingContextDescriptionProvider.java +++ b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/PepperMMEditingContextDescriptionProvider.java @@ -15,6 +15,8 @@ import pepper.starter.messages.IPepperMMMessageService; import pepper.starter.messages.MessageConstants; import pepper.peppermm.Project; +import pepper.peppermm.Resource; +import pepper.peppermm.UnavailabilityPeriod; import java.util.List; import java.util.Objects; @@ -45,6 +47,10 @@ public class PepperMMEditingContextDescriptionProvider implements IEditingContex public static final String PROJECT_FORM_ID = "projectFormDescription"; + public static final String RESOURCE_FORM_ID = "resourceFormDescription"; + + public static final String UNAVAILABILITY_PERIOD_FORM_ID = "unavailabilityPeriodFormDescription"; + private final ComposedAdapterFactory composedAdapterFactory; private final ILabelService labelService; @@ -84,6 +90,10 @@ public List getRepresentationDescriptions(IEditingCo PageDescription workpackagesPageDescription = new WorkpackagesPageDescription(this.labelService, this.identityService, this.objectSearchService, this.cursorBasedNavigationServices, this.composedAdapterFactory, this.pepperMMMessageService, this.feedbackMessageService).getWorkpackagesPageDescription(); PageDescription workpackageArtefactPageDescription = new WorkpackageArtefactPageDescription(this.labelService, this.identityService, this.objectSearchService, this.cursorBasedNavigationServices, this.composedAdapterFactory, this.pepperMMMessageService, this.feedbackMessageService).getWorkpackageArtefactsPageDescription(); PageDescription risksPageDescription = new RisksPageDescription(this.labelService, this.identityService, this.objectSearchService, this.cursorBasedNavigationServices, this.composedAdapterFactory, this.pepperMMMessageService, this.feedbackMessageService).getRisksPageDescription(); + PageDescription resourceAvailabilityPageDescription = new ResourceAvailabilityPageDescription(this.labelService, this.identityService, this.objectSearchService, this.cursorBasedNavigationServices, this.composedAdapterFactory, + this.pepperMMMessageService, this.feedbackMessageService).getPageDescription(); + PageDescription unavailabilityPeriodPageDescription = new UnavailabilityPeriodPageDescription(this.labelService, this.identityService, this.objectSearchService, this.composedAdapterFactory, this.pepperMMMessageService, + this.feedbackMessageService).getPageDescription(); FormDescription projectFormDescription = FormDescription.newFormDescription(PROJECT_FORM_ID) @@ -96,7 +106,25 @@ public List getRepresentationDescriptions(IEditingCo .pageDescriptions(List.of(projectPageDescription, customerPageDescription, planningAndCostingPageDescription, workpackagesPageDescription, workpackageArtefactPageDescription, risksPageDescription)) .iconURLsProvider(vm -> List.of()) .build(); - return List.of(projectFormDescription); + FormDescription resourceFormDescription = FormDescription.newFormDescription(RESOURCE_FORM_ID) + .label(this.pepperMMMessageService.getMessage(MessageConstants.RESOURCE_FORM_TITLE)) + .idProvider(new GetOrCreateRandomIdProvider()) + .labelProvider(variableManager -> this.pepperMMMessageService.getMessage(MessageConstants.RESOURCE_FORM_TITLE)) + .targetObjectIdProvider(this::getTargetObjectId) + .canCreatePredicate(this::canCreateResourceForm) + .pageDescriptions(List.of(resourceAvailabilityPageDescription)) + .iconURLsProvider(vm -> List.of()) + .build(); + FormDescription unavailabilityPeriodFormDescription = FormDescription.newFormDescription(UNAVAILABILITY_PERIOD_FORM_ID) + .label(this.pepperMMMessageService.getMessage(MessageConstants.UNAVAILABILITY_PERIOD_FORM_TITLE)) + .idProvider(new GetOrCreateRandomIdProvider()) + .labelProvider(variableManager -> this.pepperMMMessageService.getMessage(MessageConstants.UNAVAILABILITY_PERIOD_FORM_TITLE)) + .targetObjectIdProvider(this::getTargetObjectId) + .canCreatePredicate(this::canCreateUnavailabilityPeriodForm) + .pageDescriptions(List.of(unavailabilityPeriodPageDescription)) + .iconURLsProvider(vm -> List.of()) + .build(); + return List.of(projectFormDescription, resourceFormDescription, unavailabilityPeriodFormDescription); } private String getTargetObjectId(VariableManager variableManager) { @@ -110,4 +138,16 @@ private boolean canCreate(VariableManager variableManager) { .filter(Project.class::isInstance) .isPresent(); } + + private boolean canCreateResourceForm(VariableManager variableManager) { + return variableManager.get(VariableManager.SELF, EObject.class) + .filter(Resource.class::isInstance) + .isPresent(); + } + + private boolean canCreateUnavailabilityPeriodForm(VariableManager variableManager) { + return variableManager.get(VariableManager.SELF, EObject.class) + .filter(UnavailabilityPeriod.class::isInstance) + .isPresent(); + } } diff --git a/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/ResourceAvailabilityPageDescription.java b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/ResourceAvailabilityPageDescription.java new file mode 100644 index 0000000..0ac1d1f --- /dev/null +++ b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/ResourceAvailabilityPageDescription.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2024, 2026 CEA LIST. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + ******************************************************************************/ +package pepper.starter.services.descriptions; + +import pepper.peppermm.PepperFactory; +import pepper.peppermm.Resource; +import pepper.starter.messages.IPepperMMMessageService; +import pepper.starter.messages.MessageConstants; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +import org.eclipse.emf.edit.provider.ComposedAdapterFactory; +import org.eclipse.sirius.components.core.api.IFeedbackMessageService; +import org.eclipse.sirius.components.core.api.IIdentityService; +import org.eclipse.sirius.components.core.api.ILabelService; +import org.eclipse.sirius.components.core.api.IObjectSearchService; +import org.eclipse.sirius.components.core.api.labels.StyledString; +import org.eclipse.sirius.components.emf.tables.CursorBasedNavigationServices; +import org.eclipse.sirius.components.forms.ButtonStyle; +import org.eclipse.sirius.components.forms.WidgetIdProvider; +import org.eclipse.sirius.components.forms.description.AbstractControlDescription; +import org.eclipse.sirius.components.forms.description.ButtonDescription; +import org.eclipse.sirius.components.forms.description.GroupDescription; +import org.eclipse.sirius.components.forms.description.PageDescription; +import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.representations.VariableManager; +import org.eclipse.sirius.components.tables.descriptions.LineDescription; +import org.eclipse.sirius.components.tables.descriptions.PaginatedData; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; +import org.eclipse.sirius.components.widget.table.TableWidgetDescription; + +/** + * This class is used to provide the resource availability page description. + * + * @author Obeo + */ +public class ResourceAvailabilityPageDescription { + + public static final String UNAVAILABILITY_PERIODS_TABLE_ID = "unavailabilityPeriodsTableId"; + + private final ILabelService labelService; + + private final IIdentityService identityService; + + private final IObjectSearchService objectSearchService; + + private final CursorBasedNavigationServices cursorBasedNavigationServices; + + private final ComposedAdapterFactory composedAdapterFactory; + + private final IPepperMMMessageService pepperMMMessageService; + + private final IFeedbackMessageService feedbackMessageService; + + public ResourceAvailabilityPageDescription(ILabelService labelService, IIdentityService identityService, IObjectSearchService objectSearchService, CursorBasedNavigationServices cursorBasedNavigationServices, + ComposedAdapterFactory composedAdapterFactory, IPepperMMMessageService pepperMMMessageService, IFeedbackMessageService feedbackMessageService) { + this.labelService = labelService; + this.identityService = identityService; + this.objectSearchService = objectSearchService; + this.cursorBasedNavigationServices = cursorBasedNavigationServices; + this.composedAdapterFactory = composedAdapterFactory; + this.pepperMMMessageService = pepperMMMessageService; + this.feedbackMessageService = feedbackMessageService; + } + + PageDescription getPageDescription() { + List controlDescriptions = new ArrayList<>(); + + Function labelProvider = variableManager -> variableManager.get(VariableManager.SELF, Object.class) + .map(this.labelService::getStyledLabel) + .map(StyledString::toString) + .orElse(null); + + LineDescription lineDescription = LineDescription.newLineDescription("Unavailability Periods - Line") + .targetObjectIdProvider(this::getTargetObjectId) + .targetObjectKindProvider(this::getTargetObjectKind) + .semanticElementsProvider(this.getSemanticElementsProvider()) + .headerLabelProvider(labelProvider) + .headerIconURLsProvider(vm -> List.of()) + .headerIndexLabelProvider(vm -> "") + .initialHeightProvider(vm -> 60) + .isResizablePredicate(vm -> true) + .depthLevelProvider(vm -> 0) + .hasChildrenProvider(vm -> false) + .build(); + + WidgetDescriptionBuilderHelper widgetDescriptionBuilderHelper = new WidgetDescriptionBuilderHelper(this::getTargetObjectId, this.labelService, this.identityService, this.objectSearchService, this.composedAdapterFactory, + this.pepperMMMessageService, this.feedbackMessageService); + TableDescription tableDescription = TableDescription.newTableDescription(UNAVAILABILITY_PERIODS_TABLE_ID) + .label("") + .targetObjectIdProvider(this::getTargetObjectId) + .targetObjectKindProvider(this::getTargetObjectKind) + .labelProvider(labelProvider) + .isStripeRowPredicate(vm -> true) + .lineDescription(lineDescription) + .columnDescriptions(List.of(widgetDescriptionBuilderHelper.buildFeaturesColumnDescription(PepperFactory.eINSTANCE.createUnavailabilityPeriod()))) + .cellDescriptions(widgetDescriptionBuilderHelper.buildCellDescription()) + .iconURLsProvider(vm -> List.of()) + .enableSubRows(false) + .pageSizeOptionsProvider(vm -> List.of(10, 20)) + .defaultPageSizeIndexProvider(vm -> 1) + .build(); + + TableWidgetDescription tableWidgetDescription = TableWidgetDescription.newTableWidgetDescription("unavailabilityPeriodsTableWidgetId") + .idProvider(new WidgetIdProvider()) + .labelProvider(variableManager -> this.pepperMMMessageService.getMessage(MessageConstants.PAGE_RESOURCE_AVAILABILITY_TITLE)) + .targetObjectIdProvider(this::getTargetObjectId) + .diagnosticsProvider(variableManager -> List.of()) + .kindProvider(object -> "") + .messageProvider(object -> "") + .tableDescription(tableDescription) + .build(); + + controlDescriptions.add(tableWidgetDescription); + + GroupDescription group = GroupDescription.newGroupDescription("resourceAvailabilityGroupId") + .idProvider(variableManager -> "resourceAvailabilityGroupId") + .labelProvider(variableManager -> "") + .semanticElementsProvider(variableManager -> Collections.singletonList(variableManager.getVariables().get(VariableManager.SELF))) + .controlDescriptions(controlDescriptions) + .toolbarActionDescriptions(List.of(this.getCreateUnavailabilityPeriodButtonDescription())) + .build(); + + return PageDescription.newPageDescription("resourceAvailabilityPageId") + .idProvider(variableManager -> "resourceAvailabilityPageId") + .labelProvider(variableManager -> this.pepperMMMessageService.getMessage(MessageConstants.PAGE_RESOURCE_AVAILABILITY)) + .semanticElementsProvider(variableManager -> Collections.singletonList(variableManager.getVariables().get(VariableManager.SELF))) + .groupDescriptions(List.of(group)) + .canCreatePredicate(variableManager -> true) + .build(); + } + + private Function getSemanticElementsProvider() { + return variableManager -> variableManager.get(VariableManager.SELF, Resource.class) + .map(Resource::getUnavailabilityPeriods) + .map(periods -> this.cursorBasedNavigationServices.toPaginatedData(periods.stream().map(Object.class::cast).toList(), + variableManager.get("cursor", Object.class).orElse(null), + variableManager.get("direction", String.class).orElse(null), + variableManager.get("size", Integer.class).orElse(10))) + .orElseGet(() -> new PaginatedData(List.of(), false, false, 0)); + } + + private ButtonDescription getCreateUnavailabilityPeriodButtonDescription() { + return ButtonDescription.newButtonDescription("createUnavailabilityPeriod") + .idProvider(new WidgetIdProvider()) + .targetObjectIdProvider(this::getTargetObjectId) + .labelProvider(variableManager -> "") + .iconURLProvider(variableManager -> List.of()) + .isReadOnlyProvider(variableManager -> false) + .buttonLabelProvider(variableManager -> this.pepperMMMessageService.getMessage(MessageConstants.CREATE_NEW_UNAVAILABILITY_PERIOD)) + .imageURLProvider(variableManager -> "icons/full/obj16/UnavailabilityPeriod.svg") + .pushButtonHandler(variableManager -> { + variableManager.get(VariableManager.SELF, Resource.class) + .ifPresent(resource -> resource.getUnavailabilityPeriods().add(PepperFactory.eINSTANCE.createUnavailabilityPeriod())); + return new Success(); + }) + .diagnosticsProvider(variableManager -> List.of()) + .kindProvider(variableManager -> "") + .messageProvider(variableManager -> "") + .styleProvider(variableManager -> ButtonStyle.newButtonStyle() + .backgroundColor("#ffffff") + .foregroundColor("#261E58") + .build()) + .helpTextProvider(variableManager -> this.pepperMMMessageService.getMessage(MessageConstants.CREATE_NEW_UNAVAILABILITY_PERIOD_HELP)) + .build(); + } + + private String getTargetObjectId(VariableManager variableManager) { + return variableManager.get(VariableManager.SELF, Object.class) + .map(this.identityService::getId) + .orElse(null); + } + + private String getTargetObjectKind(VariableManager variableManager) { + return variableManager.get(VariableManager.SELF, Object.class) + .map(this.identityService::getId) + .orElse(null); + } +} diff --git a/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodPageDescription.java b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodPageDescription.java new file mode 100644 index 0000000..13735b7 --- /dev/null +++ b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodPageDescription.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2024, 2026 CEA LIST. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + ******************************************************************************/ +package pepper.starter.services.descriptions; + +import pepper.peppermm.PepperPackage; +import pepper.peppermm.UnavailabilityPeriod; +import pepper.starter.messages.IPepperMMMessageService; +import pepper.starter.messages.MessageConstants; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.function.Function; + +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.edit.provider.ComposedAdapterFactory; +import org.eclipse.sirius.components.core.api.IFeedbackMessageService; +import org.eclipse.sirius.components.core.api.IIdentityService; +import org.eclipse.sirius.components.core.api.ILabelService; +import org.eclipse.sirius.components.core.api.IObjectSearchService; +import org.eclipse.sirius.components.emf.forms.EMFFormDescriptionProvider; +import org.eclipse.sirius.components.emf.forms.EStructuralFeatureLabelProvider; +import org.eclipse.sirius.components.forms.DateTimeStyle; +import org.eclipse.sirius.components.forms.DateTimeType; +import org.eclipse.sirius.components.forms.WidgetIdProvider; +import org.eclipse.sirius.components.forms.description.DateTimeDescription; +import org.eclipse.sirius.components.forms.description.GroupDescription; +import org.eclipse.sirius.components.forms.description.PageDescription; +import org.eclipse.sirius.components.forms.description.TextfieldDescription; +import org.eclipse.sirius.components.representations.Failure; +import org.eclipse.sirius.components.representations.IStatus; +import org.eclipse.sirius.components.representations.Message; +import org.eclipse.sirius.components.representations.MessageLevel; +import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.representations.VariableManager; + +/** + * This class is used to provide the page description for an unavailability period. + * + * @author Obeo + */ +public class UnavailabilityPeriodPageDescription { + + private final ILabelService labelService; + + private final IIdentityService identityService; + + private final IObjectSearchService objectSearchService; + + private final ComposedAdapterFactory composedAdapterFactory; + + private final IPepperMMMessageService pepperMMMessageService; + + private final IFeedbackMessageService feedbackMessageService; + + private final Function semanticTargetIdProvider; + + public UnavailabilityPeriodPageDescription(ILabelService labelService, IIdentityService identityService, IObjectSearchService objectSearchService, ComposedAdapterFactory composedAdapterFactory, + IPepperMMMessageService pepperMMMessageService, IFeedbackMessageService feedbackMessageService) { + this.labelService = labelService; + this.identityService = identityService; + this.objectSearchService = objectSearchService; + this.composedAdapterFactory = composedAdapterFactory; + this.pepperMMMessageService = pepperMMMessageService; + this.feedbackMessageService = feedbackMessageService; + this.semanticTargetIdProvider = variableManager -> variableManager.get(VariableManager.SELF, Object.class).map(this.identityService::getId).orElse(null); + } + + PageDescription getPageDescription() { + WidgetDescriptionBuilderHelper widgetDescriptionBuilderHelper = new WidgetDescriptionBuilderHelper(this.semanticTargetIdProvider, this.labelService, this.identityService, this.objectSearchService, this.composedAdapterFactory, + this.pepperMMMessageService, this.feedbackMessageService); + + GroupDescription group = GroupDescription.newGroupDescription("unavailabilityPeriodGroupId") + .idProvider(variableManager -> "unavailabilityPeriodGroupId") + .labelProvider(variableManager -> "") + .semanticElementsProvider(variableManager -> Collections.singletonList(variableManager.getVariables().get(VariableManager.SELF))) + .controlDescriptions(List.of( + this.buildDateTimeDescription(PepperPackage.eINSTANCE.getUnavailabilityPeriod_StartDate()), + this.buildDateTimeDescription(PepperPackage.eINSTANCE.getUnavailabilityPeriod_EndDate()), + this.buildDescriptionTextfieldDescription(widgetDescriptionBuilderHelper))) + .build(); + + return PageDescription.newPageDescription("unavailabilityPeriodPageId") + .idProvider(variableManager -> "unavailabilityPeriodPageId") + .labelProvider(variableManager -> this.pepperMMMessageService.getMessage(MessageConstants.PAGE_RESOURCE_AVAILABILITY)) + .semanticElementsProvider(variableManager -> Collections.singletonList(variableManager.getVariables().get(VariableManager.SELF))) + .groupDescriptions(List.of(group)) + .canCreatePredicate(variableManager -> true) + .build(); + } + + private DateTimeDescription buildDateTimeDescription(EAttribute feature) { + WidgetDescriptionBuilderHelper widgetDescriptionBuilderHelper = new WidgetDescriptionBuilderHelper(this.semanticTargetIdProvider, this.labelService, this.identityService, this.objectSearchService, this.composedAdapterFactory, + this.pepperMMMessageService, this.feedbackMessageService); + + return DateTimeDescription.newDateTimeDescription(UUID.randomUUID().toString()) + .idProvider(new WidgetIdProvider()) + .type(DateTimeType.DATE) + .targetObjectIdProvider(this.semanticTargetIdProvider) + .labelProvider(this.getLabelProvider(feature)) + .isReadOnlyProvider(variableManager -> false) + .stringValueProvider(this.getDateValueProvider(feature)) + .newValueHandler(this.getDateNewValueHandler(feature)) + .diagnosticsProvider(variableManager -> List.of()) + .kindProvider(diagnostic -> "") + .messageProvider(diagnostic -> "") + .styleProvider(variableManager -> DateTimeStyle.newDateTimeStyle().widgetGridLayout(widgetDescriptionBuilderHelper.buildWidgetGridLayout()).build()) + .build(); + } + + private TextfieldDescription buildDescriptionTextfieldDescription(WidgetDescriptionBuilderHelper widgetDescriptionBuilderHelper) { + EAttribute feature = PepperPackage.eINSTANCE.getUnavailabilityPeriod_Description(); + return TextfieldDescription.newTextfieldDescription(UUID.randomUUID().toString()) + .idProvider(new WidgetIdProvider()) + .targetObjectIdProvider(this.semanticTargetIdProvider) + .labelProvider(this.getLabelProvider(feature)) + .isReadOnlyProvider(variableManager -> false) + .valueProvider(variableManager -> variableManager.get(VariableManager.SELF, UnavailabilityPeriod.class) + .map(UnavailabilityPeriod::getDescription) + .orElse("")) + .newValueHandler((variableManager, newValue) -> { + variableManager.get(VariableManager.SELF, UnavailabilityPeriod.class) + .ifPresent(period -> period.setDescription(newValue)); + return new Success(); + }) + .diagnosticsProvider(variableManager -> List.of()) + .kindProvider(diagnostic -> "") + .messageProvider(diagnostic -> "") + .styleProvider(variableManager -> org.eclipse.sirius.components.forms.TextfieldStyle.newTextfieldStyle().widgetGridLayout(widgetDescriptionBuilderHelper.buildWidgetGridLayout()).build()) + .build(); + } + + private Function getLabelProvider(EStructuralFeature feature) { + return new EStructuralFeatureLabelProvider(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE) { + @Override + public String apply(VariableManager variableManager) { + VariableManager childVM = variableManager.createChild(); + childVM.put(EMFFormDescriptionProvider.ESTRUCTURAL_FEATURE, feature); + return super.apply(childVM); + } + }; + } + + private Function getDateValueProvider(EAttribute eAttribute) { + return variableManager -> variableManager.get(VariableManager.SELF, EObject.class) + .map(eObject -> eObject.eGet(eAttribute)) + .filter(LocalDate.class::isInstance) + .map(LocalDate.class::cast) + .map(DateTimeFormatter.ISO_LOCAL_DATE::format) + .orElse(""); + } + + private BiFunction getDateNewValueHandler(EAttribute eAttribute) { + return (variableManager, newValue) -> variableManager.get(VariableManager.SELF, UnavailabilityPeriod.class) + .map(period -> this.setDate(period, eAttribute, newValue)) + .orElseGet(() -> new Failure("")); + } + + private IStatus setDate(UnavailabilityPeriod period, EAttribute eAttribute, String newValue) { + try { + LocalDate localDate = null; + if (newValue != null && !newValue.isBlank()) { + localDate = LocalDate.parse(newValue); + } + LocalDate startDate = eAttribute == PepperPackage.eINSTANCE.getUnavailabilityPeriod_StartDate() ? localDate : period.getStartDate(); + LocalDate endDate = eAttribute == PepperPackage.eINSTANCE.getUnavailabilityPeriod_EndDate() ? localDate : period.getEndDate(); + if (startDate != null && endDate != null && endDate.isBefore(startDate)) { + return new Failure(List.of(new Message(this.pepperMMMessageService.getMessage(MessageConstants.INVALID_VALUE, newValue), MessageLevel.ERROR))); + } + period.eSet(eAttribute, localDate); + return new Success(); + } catch (DateTimeParseException exception) { + return new Failure(List.of(new Message(this.pepperMMMessageService.getMessage(MessageConstants.INVALID_VALUE, newValue), MessageLevel.ERROR))); + } + } +} diff --git a/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodRowContextMenuEntryExecutor.java b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodRowContextMenuEntryExecutor.java new file mode 100644 index 0000000..197db73 --- /dev/null +++ b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodRowContextMenuEntryExecutor.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2024, 2026 CEA LIST. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + ******************************************************************************/ +package pepper.starter.services.descriptions; + +import java.util.Map; +import java.util.Objects; + +import org.eclipse.sirius.components.collaborative.api.ChangeKind; +import org.eclipse.sirius.components.collaborative.tables.api.IRowContextMenuEntryExecutor; +import org.eclipse.sirius.components.core.api.IEditService; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.core.api.IObjectSearchService; +import org.eclipse.sirius.components.representations.IStatus; +import org.eclipse.sirius.components.representations.Success; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.Table; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; +import org.springframework.stereotype.Service; + +/** + * Executes unavailability period row actions. + * + * @author Obeo + */ +@Service +public class UnavailabilityPeriodRowContextMenuEntryExecutor implements IRowContextMenuEntryExecutor { + + private final IEditService editService; + + private final IObjectSearchService objectSearchService; + + public UnavailabilityPeriodRowContextMenuEntryExecutor(IEditService editService, IObjectSearchService objectSearchService) { + this.editService = Objects.requireNonNull(editService); + this.objectSearchService = Objects.requireNonNull(objectSearchService); + } + + @Override + public boolean canExecute(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row, String rowMenuContextEntryId) { + return UnavailabilityPeriodRowContextMenuProvider.DELETE_ID.equals(rowMenuContextEntryId) + && Objects.equals(tableDescription.getId(), ResourceAvailabilityPageDescription.UNAVAILABILITY_PERIODS_TABLE_ID); + } + + @Override + public IStatus execute(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row, String rowMenuContextEntryId) { + this.objectSearchService.getObject(editingContext, row.getTargetObjectId()).ifPresent(this.editService::delete); + return new Success(ChangeKind.SEMANTIC_CHANGE, Map.of()); + } +} diff --git a/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodRowContextMenuProvider.java b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodRowContextMenuProvider.java new file mode 100644 index 0000000..e60de5c --- /dev/null +++ b/backend/pepper-starter/src/main/java/pepper/starter/services/descriptions/UnavailabilityPeriodRowContextMenuProvider.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2024, 2026 CEA LIST. + * This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Obeo - initial API and implementation + ******************************************************************************/ +package pepper.starter.services.descriptions; + +import pepper.starter.messages.IPepperMMMessageService; +import pepper.starter.messages.MessageConstants; + +import java.util.List; +import java.util.Objects; + +import org.eclipse.sirius.components.collaborative.tables.api.IRowContextMenuEntryProvider; +import org.eclipse.sirius.components.collaborative.tables.dto.RowContextMenuEntry; +import org.eclipse.sirius.components.core.api.IEditingContext; +import org.eclipse.sirius.components.tables.Line; +import org.eclipse.sirius.components.tables.Table; +import org.eclipse.sirius.components.tables.descriptions.TableDescription; +import org.springframework.stereotype.Service; + +/** + * Provides row actions for unavailability period tables. + * + * @author Obeo + */ +@Service +public class UnavailabilityPeriodRowContextMenuProvider implements IRowContextMenuEntryProvider { + + public static final String DELETE_ID = "pepper-unavailability-period-delete-row"; + + private final IPepperMMMessageService pepperMMMessageService; + + public UnavailabilityPeriodRowContextMenuProvider(IPepperMMMessageService pepperMMMessageService) { + this.pepperMMMessageService = Objects.requireNonNull(pepperMMMessageService); + } + + @Override + public boolean canHandle(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row) { + return Objects.equals(tableDescription.getId(), ResourceAvailabilityPageDescription.UNAVAILABILITY_PERIODS_TABLE_ID); + } + + @Override + public List getRowContextMenuEntries(IEditingContext editingContext, TableDescription tableDescription, Table table, Line row) { + return List.of(new RowContextMenuEntry(DELETE_ID, this.pepperMMMessageService.getMessage(MessageConstants.DELETE_UNAVAILABILITY_PERIOD), List.of())); + } +} diff --git a/backend/pepper-starter/src/main/resources/messages/pepper-starter.properties b/backend/pepper-starter/src/main/resources/messages/pepper-starter.properties index b80a2e9..fb1a71e 100644 --- a/backend/pepper-starter/src/main/resources/messages/pepper-starter.properties +++ b/backend/pepper-starter/src/main/resources/messages/pepper-starter.properties @@ -26,6 +26,13 @@ PAGE_WORKPACKAGE_ARTEFACTS= WP Artefacts PAGE_WORKPACKAGE_ARTEFACTS_TITLE= List of the workpackage Artefacts in all the workpackages of the project PAGE_RISKS= Risks PAGE_RISKS_TITLE= List of the Risks of the project +RESOURCE_FORM_TITLE=Resource Form +PAGE_RESOURCE_AVAILABILITY= Availability +PAGE_RESOURCE_AVAILABILITY_TITLE= List of resource unavailability periods +UNAVAILABILITY_PERIOD_FORM_TITLE=Unavailability Period Form +CREATE_NEW_UNAVAILABILITY_PERIOD= Create New Unavailability Period +CREATE_NEW_UNAVAILABILITY_PERIOD_HELP=Create a new unavailability period for the resource +DELETE_UNAVAILABILITY_PERIOD=Delete period CREATE_NEW_WORKPACKAGE= Create New Workpackage CREATE_NEW_WORKPACKAGE_HELP=Create a new workpackage in the project WORKPACKAGE_COLUMN_NAME=WP diff --git a/backend/pepper-starter/src/main/resources/messages/pepper-starter_fr.properties b/backend/pepper-starter/src/main/resources/messages/pepper-starter_fr.properties index 3c3018b..dbf6c09 100644 --- a/backend/pepper-starter/src/main/resources/messages/pepper-starter_fr.properties +++ b/backend/pepper-starter/src/main/resources/messages/pepper-starter_fr.properties @@ -41,3 +41,10 @@ FUNDING_HELP=Financement=Co MANPOWER_HELP=Main d'oeuvre chiffrée dans le devis interne EOTP_HELP=A compléter par le gestionnaire/assistant financier OS_HELP=Ordre Statistique\nA compléter par le gestionnaire/assistant financier +RESOURCE_FORM_TITLE=Formulaire de ressource +PAGE_RESOURCE_AVAILABILITY= Disponibilité +PAGE_RESOURCE_AVAILABILITY_TITLE= Liste des périodes d'indisponibilité de la ressource +UNAVAILABILITY_PERIOD_FORM_TITLE=Formulaire de période d'indisponibilité +CREATE_NEW_UNAVAILABILITY_PERIOD= Créer une période d'indisponibilité +CREATE_NEW_UNAVAILABILITY_PERIOD_HELP=Créer une nouvelle période d'indisponibilité pour la ressource +DELETE_UNAVAILABILITY_PERIOD=Supprimer la période