Skip to content

Commit

Permalink
Remove cancel confirmation interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
KochTobi committed Aug 30, 2024
1 parent 2e7a8d1 commit fb955cd
Show file tree
Hide file tree
Showing 25 changed files with 155 additions and 425 deletions.
Binary file modified user-interface/src/main/bundles/dev.bundle
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ private void onAddTokenClicked(AddTokenEvent addTokenEvent) {
event.personalAccessTokenDTO()
.tokenDescription(), event.personalAccessTokenDTO().expirationDate());
personalAccessTokenComponent.showCreatedToken(createdToken);
event.getSource().closeIgnoringListeners();
event.getSource().close();
Toast toast = messageSourceToastFactory.create("personal-access-token.created.success",
new Object[]{event.personalAccessTokenDTO().tokenDescription()}, getLocale());
toast.open();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ private void openChangeUserDialog() {
private void onChangeUserDetailsDialogConfirmed(ConfirmEvent event) {
var response = identityService.requestUserNameChange(userInfo.id(), event.userName());
if (response.isSuccess()) {
event.getSource().closeIgnoringListeners();
event.getSource().close();
// Trigger reload of UI reloading the username displayed in the datamanager menu
// and within this component
UI.getCurrent().getPage().reload();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,152 +1,21 @@
package life.qbic.datamanager.views.general;

import com.vaadin.flow.component.ComponentEvent;
import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.Shortcuts;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import life.qbic.datamanager.views.notifications.SupportsCloseConfirmation;
import life.qbic.datamanager.views.notifications.WithCloseListener.CloseEvent;

/**
* A {@link com.vaadin.flow.component.dialog.Dialog} with additional functionality.
* <p>
* This class adds functionality to only close on user confirmation. For this simply call
* {@link #requireCloseConfirmation()}.
*
* @see com.vaadin.flow.component.dialog.Dialog
* @since 1.4.0
*/
public class QbicDialog extends com.vaadin.flow.component.dialog.Dialog implements
SupportsCloseConfirmation<QbicDialog, CloseEvent<QbicDialog>> {

private final List<ListenerRegistration> dialogCloseListeners = new ArrayList<>();
private ListenerRegistration requireCloseConfirmationListener = null;
private boolean ignoresModificationForCloseConfirmation = SupportsCloseConfirmation.super.ignoresCloseCheckIfUnmodified();
private boolean modified = false;
public class QbicDialog extends com.vaadin.flow.component.dialog.Dialog {

public QbicDialog() {
setCloseOnOutsideClick(false);
setCloseOnEsc(false);
Shortcuts.addShortcutListener(this, this::close, Key.ESCAPE);
}

@Override
public ListenerRegistration requireCloseConfirmation() {
if (requireCloseConfirmationListener != null) {
requireCloseConfirmationListener.listenerRemover().removeListener();
}
requireCloseConfirmationListener = SupportsCloseConfirmation.super.requireCloseConfirmation();
return requireCloseConfirmationListener;
}

/**
* Remove required close confirmation. Can be used to revert {@link #requireCloseConfirmation()}
*
* @since 1.4.0
*/
public void allowCloseWithoutConfirmation() {
if (Objects.nonNull(requireCloseConfirmationListener)) {
requireCloseConfirmationListener.listenerRemover().removeListener();
}
}

/**
* Add a listener that controls whether the dialog closes or not. The listener is informed when
* the dialog is requested to close. Then you can decide whether to close or to keep opened the
* dialog. It means that dialog won't closed unless you call the {@link #closeIgnoringListeners()}
* method explicitly in the listener implementation.
* <p>
* <i>NOTE:</i>
* <b>Adding this listener changes behavior of the dialog.</b>
* <p>
* If there are no close listeners present, the {@link #close()} method closes the dialog.
* Otherwise, the existing close listeners will prevent {@link #close()} from closing the dialog.
* The listeners should call the {@link #closeIgnoringListeners()} method to close the dialog
* instead.
*
* @param listener the listener to add
* @return the resulting
* {@link life.qbic.datamanager.views.notifications.WithCloseListener.ListenerRegistration}
*/
@Override
public ListenerRegistration addCloseListener(
DialogCloseListener<QbicDialog, CloseEvent<QbicDialog>> listener) {
com.vaadin.flow.shared.Registration registration = addListener(DialogCloseEvent.class,
listener::onClose);

ListenerRegistration listenerRegistration = new ListenerRegistration(listener,
registration::remove);
dialogCloseListeners.add(listenerRegistration);
return listenerRegistration;
}

@Override
public boolean ignoresCloseCheckIfUnmodified() {
return this.ignoresModificationForCloseConfirmation;
}

/**
* Sets whether unmodified dialogs require close confirmation.
*
* @param ignore should missing modification ignore the close check?
* @param <S> the class from which the method is called.
* @return the modified dialog
*/
public <S extends QbicDialog> S setIgnoreCloseCheckIfUnmodified(boolean ignore) {
this.ignoresModificationForCloseConfirmation = ignore;
return (S) this;
}

@Override
public boolean wasModified() {
return modified;
}

@Override
public void setModified(boolean modified) {
this.modified = modified;
}

/**
* @see #close()
*/
@Override
public void closeIgnoringListeners() {
super.close();
}

/**
* Closes the dialog if no close listeners are present.
* <p>
* <p>
* If there are close listeners, instead of closing the dialog, a {@link DialogCloseEvent} is
* fired.
*/
@Override
public void close() {
if (dialogCloseListeners.isEmpty()) {
closeIgnoringListeners();
return;
}
fireEvent(new DialogCloseEvent(this, false));
}

public static class DialogCloseEvent extends ComponentEvent<QbicDialog> implements
CloseEvent<QbicDialog> {

/**
* Creates a new event using the given source and indicator whether the event originated from
* the client side or the server side.
*
* @param source the source component
* @param fromClient <code>true</code> if the event originated from the client
* side, <code>false</code> otherwise
*/
public DialogCloseEvent(QbicDialog source, boolean fromClient) {
super(source, fromClient);
}

Shortcuts.addShortcutListener(this, this::close,
Key.ESCAPE); //overwrite to point to close method instead
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected WizardDialogWindow() {
* @since 1.0.0
*/
protected void onFinishClicked(ClickEvent<Button> clickEvent) {
this.closeIgnoringListeners();
close();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ private void showAddExperimentDialog() {
private void onExperimentAddEvent(ExperimentAddEvent event) {
ProjectId projectId = context.projectId().orElseThrow();
ExperimentId createdExperiment = createExperiment(projectId, event.getExperimentDraft());
event.getSource().closeIgnoringListeners();
event.getSource().close();
displayExperimentCreationSuccess(event.getExperimentDraft().getExperimentName());
routeToExperiment(createdExperiment);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
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 loose all information entered.";
private static final String DEFAULT_CONFIRM_TEXT = "Discard Changes";
private static final Object[] EMPTY_PARAMETERS = new Object[]{};
private final MessageSource messageSource;

private static final Logger log = LoggerFactory.logger(CancelConfirmationDialogFactory.class);


public CancelConfirmationDialogFactory(MessageSource messageSource) {
this.messageSource = messageSource;
}

public NotificationDialog cancelConfirmationDialog(Consumer<ConfirmEvent> onCancelConfirmed,
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);

confirmCancelDialog.addCancelListener(event -> event.getSource().close());

confirmCancelDialog.addConfirmListener(event -> {
event.getSource().close();
onCancelConfirmed.accept(event);
});
return confirmCancelDialog;

}

private static com.vaadin.flow.component.Component createContentComponent(MessageType contentType,
String contentText) {
return switch (contentType) {
case HTML -> new Html("<div style=\"display:contents\">%s</div>".formatted(contentText));
case TEXT -> new Span(contentText);
};
}

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.error("No message type specified for %s." + key, e);
return DEFAULT_MESSAGE_TYPE;
}
}

private enum MessageType {
HTML,
TEXT
}
}

This file was deleted.

Loading

0 comments on commit fb955cd

Please sign in to comment.