From 9ea1a9bfd72ad00fd2df230f6cb57e7bcc16151b Mon Sep 17 00:00:00 2001 From: Sven Fillinger Date: Mon, 27 Jul 2026 19:14:47 +0200 Subject: [PATCH 1/6] refactor: migrate all NotificationDialog to AlertDialog and remove factories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace all NotificationDialog subclasses with AlertDialog patterns: - Deleted 10 NotificationDialog subclasses (dead-simple factories with zero reusable logic): AccessTokenDeletionConfirmationNotification, BatchDeletionConfirmationNotification, MeasurementDeletionConfirmationNotification, QCItemDeletionConfirmationNotification, PurchaseItemDeletionConfirmationNotification, ProjectUserRemovalConfirmationNotification, ExistingGroupsPreventVariableEdit, ExistingSamplesPreventVariableEdit, ExistingSamplesPreventSampleOriginEdit, ExistingSamplesPreventGroupEdit - Deleted CancelConfirmationDialogFactory — callers now use AlertDialog.alert().warning() directly - Deprecated MessageSourceNotificationFactory.dialog() — single call-site inlined as AlertDialog - Converted NotificationDialog.java to deprecated stub throwing UnsupportedOperationException - Migrated UiExceptionHandler to AlertDialog - Updated front-end-components.md with AlertDialog pattern documentation GitHub Issue: #1487 --- datamanager-app/front-end-components.md | 122 +++++++++++ .../exceptionhandling/UiExceptionHandler.java | 12 +- ...TokenDeletionConfirmationNotification.java | 24 -- .../account/PersonalAccessTokenMain.java | 23 +- .../ProjectSideNavigationComponent.java | 21 +- .../CancelConfirmationDialogFactory.java | 113 ---------- .../MessageSourceNotificationFactory.java | 23 +- .../notifications/NotificationDialog.java | 207 ++++-------------- .../projects/create/AddProjectDialog.java | 19 +- .../overview/ProjectOverviewMain.java | 7 +- .../projects/project/ProjectMainLayout.java | 3 - .../access/ProjectAccessComponent.java | 25 ++- ...ctUserRemovalConfirmationNotification.java | 26 --- .../experiments/ExperimentMainLayout.java | 4 +- .../ExistingSamplesPreventGroupEdit.java | 34 --- .../ExperimentDetailsComponent.java | 27 ++- .../ExistingGroupsPreventVariableEdit.java | 47 ---- ...xistingSamplesPreventSampleOriginEdit.java | 29 --- .../ExistingSamplesPreventVariableEdit.java | 35 --- .../update/EditExperimentDialog.java | 17 +- .../project/info/ProjectInformationMain.java | 58 +++-- ...ementDeletionConfirmationNotification.java | 22 -- .../project/measurements/MeasurementMain.java | 40 ++-- ...BatchDeletionConfirmationNotification.java | 23 -- .../samples/SampleInformationMain.java | 48 ++-- ...eItemDeletionConfirmationNotification.java | 23 -- ...CItemDeletionConfirmationNotification.java | 22 -- 27 files changed, 317 insertions(+), 737 deletions(-) delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/account/AccessTokenDeletionConfirmationNotification.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/CancelConfirmationDialogFactory.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/project/access/ProjectUserRemovalConfirmationNotification.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/project/experiments/experiment/ExistingSamplesPreventGroupEdit.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/project/experiments/experiment/components/ExistingGroupsPreventVariableEdit.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/project/experiments/experiment/components/ExistingSamplesPreventSampleOriginEdit.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/project/experiments/experiment/components/ExistingSamplesPreventVariableEdit.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/project/measurements/MeasurementDeletionConfirmationNotification.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/project/samples/BatchDeletionConfirmationNotification.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/purchase/PurchaseItemDeletionConfirmationNotification.java delete mode 100644 datamanager-app/src/main/java/life/qbic/datamanager/views/projects/qualityControl/QCItemDeletionConfirmationNotification.java diff --git a/datamanager-app/front-end-components.md b/datamanager-app/front-end-components.md index 6faad7e531..287919ea4b 100644 --- a/datamanager-app/front-end-components.md +++ b/datamanager-app/front-end-components.md @@ -136,5 +136,127 @@ classDiagram ``` +## Alert dialog + +```mermaid +classDiagram + note for Component "Vaadin Component" + AlertDialog <-- AppDialog + AppDialog --> DialogHeader + AppDialog --> DialogBody + AppDialog --> DialogFooter + AppDialog --|> Dialog + + class AlertDialog { + <> + +alert(Component parent) Builder + +danger(Component parent, String title, String message, DialogAction onConfirm) AlertDialog + +open() + +close() + +dialog() AppDialog + } + + class Builder { + +intent(Intent intent) Builder + +danger() Builder + +warning() Builder + +error() Builder + +info() Builder + +title(String title) Builder + +message(String message) Builder + +confirmButton(String label, DialogAction action) Builder + +cancelButton(String label, DialogAction action) Builder + +build() AlertDialog + } + + class AppDialog { + +small() AppDialog + +registerConfirmAction(DialogAction action) + +registerCancelAction(DialogAction action) + +open() + +close() + } + + class DialogHeader { + +withIcon(AppDialog dialog, String title, Icon icon) + } + + class DialogBody { + +withoutUserInput(AppDialog dialog, Component component) + } + + class DialogFooter { + +withDangerousConfirm(AppDialog dialog, String cancelText, String confirmText) + +with(AppDialog dialog, String cancelText, String confirmText) + +withConfirmOnly(AppDialog dialog, String confirmText) + } + + class DialogAction { + <> + +execute() + } +``` + +### When to use + +| Need | Pattern | +|---|---| +| Destructive action confirmation | `AlertDialog.danger(parent, title, message, onConfirm).open()` | +| Error requiring acknowledgment | `AlertDialog.alert(parent).error().title(...).message(...).confirmButton("OK", () -> {}).build().open()` | +| Error with redirect + cancel | `AlertDialog.alert(parent).error().confirmButton("Go...", nav).cancelButton("Cancel", close).build().open()` | +| Cancel / discard changes | `CancelConfirmationDialogFactory.cancelConfirmationDialog(action, key, locale).open()` | +| Success / info / transient feedback | `MessageSourceNotificationFactory.toast(...)` (unchanged) | +| Pending task with progress bar | `MessageSourceNotificationFactory.pendingTaskToast(...)` (unchanged) | + +### Code examples + +**Destructive confirmation (most common):** +```java +AlertDialog.danger(this, + "Samples within batch will be deleted", + "Deleting this Batch will also delete the samples contained within. Proceed?", + () -> deleteBatch(batchId)).open(); +``` + +**Error dialog with single button:** +```java +AlertDialog.alert(this) + .error() + .title("Cannot edit variables") + .message("Editing experimental variables is only possible if samples are not registered.") + .confirmButton("Okay", () -> {}) + .build() + .open(); +``` + +**Warning with cancel:** +```java +AlertDialog.alert(this) + .warning() + .title("Discard changes?") + .message("By aborting, you will lose all entered information.") + .confirmButton("Discard", () -> discard()) + .cancelButton("Continue Editing", () -> {}) // close dialog + .build() + .open(); +``` + +### Deprecated: NotificationDialog + +`NotificationDialog` has been removed and replaced with `AlertDialog`. The following classes were deleted: + +- `AccessTokenDeletionConfirmationNotification` +- `BatchDeletionConfirmationNotification` +- `MeasurementDeletionConfirmationNotification` +- `QCItemDeletionConfirmationNotification` +- `PurchaseItemDeletionConfirmationNotification` +- `ProjectUserRemovalConfirmationNotification` +- `ExistingGroupsPreventVariableEdit` +- `ExistingSamplesPreventVariableEdit` +- `ExistingSamplesPreventSampleOriginEdit` +- `ExistingSamplesPreventGroupEdit` + +If any code still references `NotificationDialog`, it will throw `UnsupportedOperationException` at runtime. Use the patterns above instead. + diff --git a/datamanager-app/src/main/java/life/qbic/datamanager/exceptionhandling/UiExceptionHandler.java b/datamanager-app/src/main/java/life/qbic/datamanager/exceptionhandling/UiExceptionHandler.java index 1de0d7e423..bdf132098f 100644 --- a/datamanager-app/src/main/java/life/qbic/datamanager/exceptionhandling/UiExceptionHandler.java +++ b/datamanager-app/src/main/java/life/qbic/datamanager/exceptionhandling/UiExceptionHandler.java @@ -5,13 +5,12 @@ import static life.qbic.logging.service.LoggerFactory.logger; import com.vaadin.flow.component.UI; -import com.vaadin.flow.component.html.Span; import com.vaadin.flow.server.ErrorEvent; import java.net.InetAddress; import java.net.UnknownHostException; import life.qbic.application.commons.ApplicationException; import life.qbic.datamanager.exceptionhandling.ErrorMessageTranslationService.UserFriendlyErrorMessage; -import life.qbic.datamanager.views.notifications.NotificationDialog; +import life.qbic.datamanager.views.general.dialog.AlertDialog; import life.qbic.logging.api.Logger; import life.qbic.projectmanagement.application.associated_dataset.AssociatedDatasetServiceException; import org.springframework.beans.factory.annotation.Autowired; @@ -126,9 +125,12 @@ private boolean isUiReady(UI ui) { } private void showErrorDialog(UserFriendlyErrorMessage userFriendlyError) { - NotificationDialog.errorDialog() - .withTitle(userFriendlyError.title()) - .withContent(new Span(userFriendlyError.message())) + AlertDialog.alert(UI.getCurrent()) + .error() + .title(userFriendlyError.title()) + .message(userFriendlyError.message()) + .confirmButton("Okay", () -> {}) + .build() .open(); } } diff --git a/datamanager-app/src/main/java/life/qbic/datamanager/views/account/AccessTokenDeletionConfirmationNotification.java b/datamanager-app/src/main/java/life/qbic/datamanager/views/account/AccessTokenDeletionConfirmationNotification.java deleted file mode 100644 index b8dee23bb5..0000000000 --- a/datamanager-app/src/main/java/life/qbic/datamanager/views/account/AccessTokenDeletionConfirmationNotification.java +++ /dev/null @@ -1,24 +0,0 @@ -package life.qbic.datamanager.views.account; - -import com.vaadin.flow.component.html.Span; -import life.qbic.datamanager.views.notifications.NotificationDialog; -import life.qbic.datamanager.views.notifications.NotificationLevel; - -/** - * Warns the user that the personal access token will be deleted and cannot be used - *

- * This dialog is to be shown when PAT delection is triggered by the user. - */ -public class AccessTokenDeletionConfirmationNotification extends NotificationDialog { - - public AccessTokenDeletionConfirmationNotification() { - super(NotificationLevel.WARNING); - withTitle("Personal Access Token will be deleted"); - withContent(new Span( - "Deleting this Personal Access Token will make it unusable. Proceed?")); - setCancelable(true); - setConfirmText("Delete Token"); - } - - -} diff --git a/datamanager-app/src/main/java/life/qbic/datamanager/views/account/PersonalAccessTokenMain.java b/datamanager-app/src/main/java/life/qbic/datamanager/views/account/PersonalAccessTokenMain.java index a0ea248599..8c15197d33 100644 --- a/datamanager-app/src/main/java/life/qbic/datamanager/views/account/PersonalAccessTokenMain.java +++ b/datamanager-app/src/main/java/life/qbic/datamanager/views/account/PersonalAccessTokenMain.java @@ -18,6 +18,7 @@ import life.qbic.datamanager.views.account.PersonalAccessTokenComponent.DeleteTokenEvent; import life.qbic.datamanager.views.account.PersonalAccessTokenComponent.PersonalAccessTokenFrontendBean; import life.qbic.datamanager.views.general.Main; +import life.qbic.datamanager.views.general.dialog.AlertDialog; import life.qbic.datamanager.views.notifications.MessageSourceNotificationFactory; import life.qbic.datamanager.views.notifications.Toast; import life.qbic.identity.api.PersonalAccessToken; @@ -74,18 +75,16 @@ public PersonalAccessTokenMain(PersonalAccessTokenService personalAccessTokenSer } private void onDeleteTokenClicked(DeleteTokenEvent deleteTokenEvent) { - AccessTokenDeletionConfirmationNotification tokenDeletionConfirmationNotification = new AccessTokenDeletionConfirmationNotification(); - tokenDeletionConfirmationNotification.open(); - tokenDeletionConfirmationNotification.addConfirmListener(event -> { - var userId = userIdTranslator.translateToUserId( - SecurityContextHolder.getContext().getAuthentication()) - .orElseThrow(); - personalAccessTokenService.delete(deleteTokenEvent.tokenId(), userId); - loadGeneratedPersonalAccessTokens(); - tokenDeletionConfirmationNotification.close(); - }); - tokenDeletionConfirmationNotification.addCancelListener( - event -> tokenDeletionConfirmationNotification.close()); + AlertDialog.danger(this, + "Personal Access Token will be deleted", + "Deleting this Personal Access Token will make it unusable. Proceed?", + () -> { + var userId = userIdTranslator.translateToUserId( + SecurityContextHolder.getContext().getAuthentication()) + .orElseThrow(); + personalAccessTokenService.delete(deleteTokenEvent.tokenId(), userId); + loadGeneratedPersonalAccessTokens(); + }).open(); } private void onAddTokenClicked(AddTokenEvent addTokenEvent) { diff --git a/datamanager-app/src/main/java/life/qbic/datamanager/views/navigation/ProjectSideNavigationComponent.java b/datamanager-app/src/main/java/life/qbic/datamanager/views/navigation/ProjectSideNavigationComponent.java index 4c97837e27..dd8484f682 100644 --- a/datamanager-app/src/main/java/life/qbic/datamanager/views/navigation/ProjectSideNavigationComponent.java +++ b/datamanager-app/src/main/java/life/qbic/datamanager/views/navigation/ProjectSideNavigationComponent.java @@ -32,9 +32,8 @@ import life.qbic.datamanager.security.UserPermissions; import life.qbic.datamanager.views.AppRoutes.ProjectRoutes; import life.qbic.datamanager.views.Context; -import life.qbic.datamanager.views.notifications.CancelConfirmationDialogFactory; +import life.qbic.datamanager.views.general.dialog.AlertDialog; import life.qbic.datamanager.views.notifications.MessageSourceNotificationFactory; -import life.qbic.datamanager.views.notifications.NotificationDialog; import life.qbic.datamanager.views.notifications.Toast; import life.qbic.datamanager.views.projects.overview.ProjectOverviewMain; import life.qbic.datamanager.views.projects.project.ProjectMainLayout; @@ -79,7 +78,6 @@ public class ProjectSideNavigationComponent extends Div implements private final transient ExperimentInformationService experimentInformationService; private final transient AddExperimentToProjectService addExperimentToProjectService; private final transient UserPermissions userPermissions; - private final transient CancelConfirmationDialogFactory cancelConfirmationDialogFactory; private final transient MessageSourceNotificationFactory messageSourceNotificationFactory; private final transient TerminologyService terminologyService; private final transient SpeciesLookupService speciesLookupService; @@ -92,7 +90,6 @@ public ProjectSideNavigationComponent( UserPermissions userPermissions, SpeciesLookupService speciesLookupService, TerminologyService terminologyService, - CancelConfirmationDialogFactory cancelConfirmationDialogFactory, MessageSourceNotificationFactory messageSourceNotificationFactory) { content = new Div(); requireNonNull(projectInformationService); @@ -100,8 +97,6 @@ public ProjectSideNavigationComponent( requireNonNull(addExperimentToProjectService); this.messageSourceNotificationFactory = requireNonNull(messageSourceNotificationFactory, "messageSourceNotificationFactory must not be null"); - this.cancelConfirmationDialogFactory = requireNonNull(cancelConfirmationDialogFactory, - "cancelConfirmationDialogFactory must not be null"); this.speciesLookupService = speciesLookupService; this.addExperimentToProjectService = addExperimentToProjectService; this.userPermissions = requireNonNull(userPermissions, "userPermissions must not be null"); @@ -340,12 +335,14 @@ private void showAddExperimentDialog() { } private void showCancelConfirmationDialog(AddExperimentDialog creationDialog) { - NotificationDialog confirmationDialog = cancelConfirmationDialogFactory.cancelConfirmationDialog( - it -> creationDialog.close(), - "experiment.create", - getLocale() - ); - confirmationDialog.open(); + AlertDialog.alert(this) + .warning() + .title("Discard changes?") + .message("By aborting the editing process and closing the dialog, you will lose all information entered.") + .confirmButton("Discard changes", creationDialog::close) + .cancelButton("Continue editing", () -> {}) + .build() + .open(); } private void onExperimentAddEvent(ExperimentAddEvent event) { diff --git a/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/CancelConfirmationDialogFactory.java b/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/CancelConfirmationDialogFactory.java deleted file mode 100644 index 0bd3895cf8..0000000000 --- a/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/CancelConfirmationDialogFactory.java +++ /dev/null @@ -1,113 +0,0 @@ -package life.qbic.datamanager.views.notifications; - -import com.vaadin.flow.component.Html; -import com.vaadin.flow.component.button.Button; -import com.vaadin.flow.component.confirmdialog.ConfirmDialog.ConfirmEvent; -import com.vaadin.flow.component.html.Span; -import java.util.Locale; -import java.util.function.Consumer; -import life.qbic.logging.api.Logger; -import life.qbic.logging.service.LoggerFactory; -import org.springframework.context.MessageSource; -import org.springframework.context.NoSuchMessageException; -import org.springframework.stereotype.Component; - -@Component -public class CancelConfirmationDialogFactory { - - private static final MessageType DEFAULT_MESSAGE_TYPE = MessageType.HTML; //set to html as text works with it too - private static final String DEFAULT_TITLE = "Discard Changes?"; - private static final String DEFAULT_CONTENT = "By aborting the editing process and closing the dialog, you will lose all information entered."; - private static final String DEFAULT_CONFIRM_TEXT = "Discard Changes"; - private static final Object[] EMPTY_PARAMETERS = new Object[]{}; - private static final Logger log = LoggerFactory.logger(CancelConfirmationDialogFactory.class); - private final MessageSource messageSource; - - - public CancelConfirmationDialogFactory(MessageSource messageSource) { - this.messageSource = messageSource; - } - - private static com.vaadin.flow.component.Component createContentComponent(MessageType contentType, - String contentText) { - return switch (contentType) { - case HTML -> new Html("

%s
".formatted(contentText)); - case TEXT -> new Span(contentText); - }; - } - - /** - * Creates an instance of an {@link NotificationDialog} with title and message based on the - * provided key. - * - * @param key The message key to determine the content and title of the {@link NotificationDialog}. - * @param locale - * @return the notification dialog - * @since - */ - public NotificationDialog cancelConfirmationDialog(String key, Locale locale) { - return buildDialog(key, locale); - } - - public NotificationDialog cancelConfirmationDialog(Consumer onCancelConfirmed, - String key, Locale locale) { - var confirmCancelDialog = buildDialog(key, locale); - confirmCancelDialog.addCancelListener(event -> event.getSource().close()); - - confirmCancelDialog.addConfirmListener(event -> { - event.getSource().close(); - onCancelConfirmed.accept(event); - }); - return confirmCancelDialog; - } - - private NotificationDialog buildDialog(String key, Locale locale) { - String title = parseTitle(key, locale); - MessageType contentType = parseMessageType(key, locale); - String contentText = parseMessageText(key, locale); - String confirmText = parseConfirmText(key, locale); - var content = createContentComponent(contentType, contentText); - - NotificationDialog confirmCancelDialog = NotificationDialog.warningDialog() - .withTitle(title) - .withContent(content); - confirmCancelDialog.setCancelable(true); - confirmCancelDialog.setCancelText("Continue Editing"); - Button redButton = new Button(confirmText); - redButton.addClassName("danger"); - confirmCancelDialog.setConfirmButton(redButton); - return confirmCancelDialog; - } - - private String parseConfirmText(String key, Locale locale) { - return messageSource.getMessage("%s.cancel-confirmation.confirm-text".formatted(key), - new Object[]{}, DEFAULT_CONFIRM_TEXT, locale); - } - - private String parseMessageText(String key, Locale locale) { - return messageSource.getMessage("%s.cancel-confirmation.message.text".formatted(key), - new Object[]{}, DEFAULT_CONTENT, locale); - } - - private String parseTitle(String key, Locale locale) { - return messageSource.getMessage("%s.cancel-confirmation.title".formatted(key), - new Object[]{}, DEFAULT_TITLE, locale); - } - - private MessageType parseMessageType(String key, Locale locale) { - try { - String messageType = messageSource.getMessage( - "%s.cancel-confirmation.message.type".formatted(key), - EMPTY_PARAMETERS, locale).strip().toUpperCase(); - return MessageType.valueOf(messageType); - } catch (NoSuchMessageException e) { - log.warn("No message type specified for %s.".formatted(key)); - return DEFAULT_MESSAGE_TYPE; - } - } - - private enum MessageType { - HTML, - TEXT - } -} diff --git a/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/MessageSourceNotificationFactory.java b/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/MessageSourceNotificationFactory.java index e29baf3e49..2de40f375b 100644 --- a/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/MessageSourceNotificationFactory.java +++ b/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/MessageSourceNotificationFactory.java @@ -13,6 +13,7 @@ import java.time.format.DateTimeParseException; import java.util.Locale; import java.util.Optional; +import life.qbic.datamanager.views.general.dialog.AlertDialog; import life.qbic.logging.api.Logger; import org.springframework.context.MessageSource; import org.springframework.context.NoSuchMessageException; @@ -139,26 +140,12 @@ public Toast pendingTaskToast(String key, Object[] messageArgs, Locale locale) { } /** - * Creates a dialog notification with the contents found for the message key. This method produces - * a notification dialog with the link text read from the message properties file. + * Creates a dialog notification with the contents found for the message key. * - *

- * The following message keys have to be present: - *

    - *
  • {@code .title} - the title; optional - *
  • {@code .level} - the level; mandatory - *
  • {@code .message.type} - the type (text or html); mandatory - *
  • {@code .message.text} - the text; mandatory - *
  • {@code .confirm-text} - the text of the confirm button; optional - *
- *

- * For more information please see dialog-notifications.properties - * - * @param key the key for the messages - * @param parameters parameters to use in the message - * @param locale the locale for which to load the message - * @return a notification dialog with loaded content + * @deprecated Use {@link AlertDialog} directly instead. This method will be removed in a future + * version. See {@code front-end-components.md} for the migration guide. */ + @Deprecated(since = "1.12.0", forRemoval = true) public NotificationDialog dialog(String key, Object[] parameters, Locale locale) { MessageType type = parseMessageType(key, locale); String messageText = parseMessage(key, parameters, locale); diff --git a/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/NotificationDialog.java b/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/NotificationDialog.java index 8f3a9b1e3b..a6df65f8a2 100644 --- a/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/NotificationDialog.java +++ b/datamanager-app/src/main/java/life/qbic/datamanager/views/notifications/NotificationDialog.java @@ -1,200 +1,81 @@ package life.qbic.datamanager.views.notifications; -import static java.util.Objects.requireNonNull; - import com.vaadin.flow.component.Component; -import com.vaadin.flow.component.confirmdialog.ConfirmDialog; -import com.vaadin.flow.component.html.Div; -import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.html.Span; -import com.vaadin.flow.component.icon.Icon; -import com.vaadin.flow.component.icon.VaadinIcon; -import com.vaadin.flow.dom.Style.Display; -import com.vaadin.flow.router.BeforeLeaveEvent; -import com.vaadin.flow.router.BeforeLeaveObserver; +import life.qbic.datamanager.views.general.dialog.AlertDialog; /** - * A dialog notifying the user of some event. - *

- * By default, this dialog comes with an icon and a text in the header. You can modify the header - * text with {@link #withTitle}. When setting the icon with {@link #withHeaderIcon}, you can modify - * the color of the icon by assigning the following css classes: - *

    - *
  • success-icon
  • - *
  • warning-icon
  • - *
  • error-icon
  • - *
  • info-icon
  • - *
- * The dialog itself is assigned a corresponding CSS class - *
    - *
  • success-dialog
  • - *
  • warning-dialog
  • - *
  • error-dialog
  • - *
  • info-dialog
  • - *
+ * Deprecated: NotificationDialog + * + *

This class has been removed. Use {@link life.qbic.datamanager.views.general.dialog.AlertDialog} + * instead. See {@code front-end-components.md} for the migration guide.

+ * + * @deprecated Use {@link life.qbic.datamanager.views.general.dialog.AlertDialog} directly. + * This class is a placeholder for backward compatibility only and should not be + * instantiated. It will be removed in a future version. + * @since 1.12.0 */ -public class NotificationDialog extends ConfirmDialog implements BeforeLeaveObserver { +@Deprecated(since = "1.12.0", forRemoval = true) +public final class NotificationDialog { - private final H2 title; private final NotificationLevel level; - protected final Div layout; - private Icon headerIcon; - protected Component content; protected NotificationDialog(NotificationLevel level) { - addClassName("notification-dialog"); - addClassName(switch (level) { - case SUCCESS -> "success-dialog"; - case WARNING -> "warning-dialog"; - case ERROR -> "error-dialog"; - case INFO -> "info-dialog"; - }); - this.level = requireNonNull(level, "level must not be null"); - - var defaultTitle = switch (level) { - case SUCCESS -> "Success"; - case WARNING -> "Warning"; - case ERROR -> "Error"; - case INFO -> "Please note"; - }; - title = new H2(defaultTitle); - title.addClassName("title"); - withHeaderIcon(typeBasedHeaderIcon(this.level)); - updateHeader(); - - layout = new Div(); - layout.addClassName("content"); - this.content = new Div(); - layout.add(this.content); - setText(layout); - setConfirmText("Okay"); - } - - protected static Icon typeBasedHeaderIcon(NotificationLevel notificationLevel) { - var iconCssClass = switch (notificationLevel) { - case SUCCESS -> "success-icon"; - case WARNING -> "warning-icon"; - case ERROR -> "error-icon"; - case INFO -> "info-icon"; - }; - var icon = switch (notificationLevel) { - case SUCCESS -> VaadinIcon.CHECK.create(); - case WARNING -> VaadinIcon.WARNING.create(); - case ERROR -> VaadinIcon.CLOSE_CIRCLE.create(); - case INFO -> VaadinIcon.INFO_CIRCLE.create(); - }; - icon.addClassName(iconCssClass); - return icon; - } - - /** - * Creates a new notification dialog - * - * @return a notification dialog showing a success notification - */ - public static NotificationDialog successDialog() { - return new NotificationDialog(NotificationLevel.SUCCESS); + this.level = level; } /** - * Creates a new notification dialog - * - * @return a notification dialog showing a warning notification - */ - public static NotificationDialog warningDialog() { - return new NotificationDialog(NotificationLevel.WARNING); - } - - /** - * Creates a new notification dialog - * - * @return a notification dialog showing an error notification + * @deprecated This method throws UnsupportedOperationException. Use {@link AlertDialog} instead. */ + @Deprecated(since = "1.12.0", forRemoval = true) public static NotificationDialog errorDialog() { - return new NotificationDialog(NotificationLevel.ERROR); + throw new UnsupportedOperationException( + "NotificationDialog.errorDialog() has been removed. " + + "Use AlertDialog.alert(parent).error().title(...).message(...).confirmButton(...).build().open()"); } /** - * Creates a new notification dialog - * - * @return a notification dialog showing an info notification + * @deprecated This method throws UnsupportedOperationException. Use {@link AlertDialog} instead. */ - public static NotificationDialog infoDialog() { - return new NotificationDialog(NotificationLevel.INFO); - } - - private void updateHeader() { - setHeader(new Span(headerIcon, title)); - } - - /** - * Changes the header icon to the icon specified. - * - * @param icon the icon to display in the header - * @param - * @return a modified notification dialog - */ - public T withHeaderIcon(Icon icon) { - this.headerIcon = icon; - updateHeader(); - return (T) this; + @Deprecated(since = "1.12.0", forRemoval = true) + public static NotificationDialog warningDialog() { + throw new UnsupportedOperationException( + "NotificationDialog.warningDialog() has been removed. " + + "Use AlertDialog.alert(parent).warning().title(...).message(...).build().open()"); } /** - * Changes the title of the dialog. Does not touch the icon. - * - * @param text the title of the dialog - * @param - * @return a dialog with the provided title + * @deprecated This method throws UnsupportedOperationException. Use {@link AlertDialog} instead. */ + @Deprecated(since = "1.12.0", forRemoval = true) public T withTitle(String text) { - title.setText(text); - updateHeader(); - return (T) this; + throw new UnsupportedOperationException( + "NotificationDialog.withTitle() has been removed. Use AlertDialog instead."); } /** - * Sets the content of the dialog. - *

- * The content can be any {@link Component}. Previous content is removed from the dialog when - * calling this method. The content provided must not be null but can be any empty component. - * - * @param content the new content of the dialog - * @param - * @return the modified dialog + * @deprecated This method throws UnsupportedOperationException. Use {@link AlertDialog} instead. */ + @Deprecated(since = "1.12.0", forRemoval = true) public T withContent(Component content) { - if (this.content != null) { - this.content.removeFromParent(); - } - this.content = requireNonNull(content, "content must not be null"); - layout.removeAll(); - layout.add(this.content); - return (T) this; + throw new UnsupportedOperationException( + "NotificationDialog.withContent() has been removed. Use AlertDialog instead."); } /** - * Sets the content of the dialog. - *

- * The content can be any number of {@link Component}s. At least one component is required. - *

- * Previous content is removed from the dialog when calling this method. - * - * @param content the new content of the dialog - * @param - * @return the modified dialog + * @deprecated This method throws UnsupportedOperationException. Use {@link AlertDialog} instead. */ - public T withContent(Component... content) { - if (content.length <= 0) { - throw new IllegalArgumentException("Content must have at least one element"); - } - Div hiddenCollectionDiv = new Div(content); - hiddenCollectionDiv.getStyle().setDisplay(Display.CONTENTS); - return withContent(hiddenCollectionDiv); + @Deprecated(since = "1.12.0", forRemoval = true) + public void setConfirmText(String text) { + throw new UnsupportedOperationException( + "NotificationDialog.setConfirmText() has been removed. Use AlertDialog instead."); } - @Override - public void beforeLeave(BeforeLeaveEvent event) { - this.close(); + /** + * @deprecated This method throws UnsupportedOperationException. Use {@link AlertDialog} instead. + */ + @Deprecated(since = "1.12.0", forRemoval = true) + public void open() { + throw new UnsupportedOperationException( + "NotificationDialog.open() has been removed. Use AlertDialog instead."); } } diff --git a/datamanager-app/src/main/java/life/qbic/datamanager/views/projects/create/AddProjectDialog.java b/datamanager-app/src/main/java/life/qbic/datamanager/views/projects/create/AddProjectDialog.java index ccad715077..8fff240d0f 100644 --- a/datamanager-app/src/main/java/life/qbic/datamanager/views/projects/create/AddProjectDialog.java +++ b/datamanager-app/src/main/java/life/qbic/datamanager/views/projects/create/AddProjectDialog.java @@ -24,8 +24,6 @@ import life.qbic.datamanager.views.general.Stepper; import life.qbic.datamanager.views.general.Stepper.StepIndicator; import life.qbic.datamanager.views.general.funding.FundingEntry; -import life.qbic.datamanager.views.notifications.CancelConfirmationDialogFactory; -import life.qbic.datamanager.views.notifications.NotificationDialog; import life.qbic.datamanager.views.projects.create.CollaboratorsLayout.ProjectCollaborators; import life.qbic.datamanager.views.projects.create.ExperimentalInformationLayout.ExperimentalInformation; import life.qbic.datamanager.views.projects.create.ProjectDesignLayout.ProjectDesign; @@ -61,7 +59,6 @@ public class AddProjectDialog extends QbicDialog { private final Button nextButton; private final Map stepContent; - private final transient CancelConfirmationDialogFactory cancelConfirmationDialogFactory; private StepIndicator addStep(Stepper stepper, String label, Component layout) { stepContent.put(label, layout); @@ -71,8 +68,7 @@ private StepIndicator addStep(Stepper stepper, String label, Component layout) { public AddProjectDialog(ProjectInformationService projectInformationService, FinanceService financeService, PersonLookupService personLookupService, - SpeciesLookupService speciesLookupService, TerminologyService terminologyService, - CancelConfirmationDialogFactory cancelConfirmationDialogFactory) { + SpeciesLookupService speciesLookupService, TerminologyService terminologyService) { super(); addClassName("add-project-dialog"); @@ -81,8 +77,6 @@ public AddProjectDialog(ProjectInformationService projectInformationService, requireNonNull(personLookupService, "personLookupService must not be null"); requireNonNull(speciesLookupService, "ontologyTermInformationService must not be null"); - this.cancelConfirmationDialogFactory = requireNonNull(cancelConfirmationDialogFactory, - "cancelConfirmationDialogFactory must not be null"); this.projectDesignLayout = new ProjectDesignLayout(projectInformationService, financeService); this.fundingInformationLayout = new FundingInformationLayout(); this.collaboratorsLayout = new CollaboratorsLayout(personLookupService); @@ -147,9 +141,14 @@ public void enableOfferSearch() { } private void onCancelClicked() { - NotificationDialog cancelConfirmationDialog = cancelConfirmationDialogFactory.cancelConfirmationDialog( - it -> close(), "project.create", getLocale()); - cancelConfirmationDialog.open(); + life.qbic.datamanager.views.general.dialog.AlertDialog.alert(this) + .warning() + .title("Discard changes?") + .message("By aborting the editing process and closing the dialog, you will lose all information entered.") + .confirmButton("Discard changes", () -> close()) + .cancelButton("Continue editing", () -> {}) + .build() + .open(); } private void onConfirmClicked(ClickEvent