vaadin / flow-components

Java counterpart of Vaadin Web Components
101 stars 66 forks source link

Notification's controls aren't clickable anymore when opening a new Dialog while Notification is still visible #3498

Open mil3stone opened 2 years ago

mil3stone commented 2 years ago

Description

When opening a modal Dialog after a Notification is shown, the controls inside the Notification aren't clickable anymore. They aren't disabled, it is more like their respective ClickListeners were disabled. You first have to close the Dialog (which is behind the Notification) to make the Notification's button work again.

non-closable-notification

Expected outcome

I would expect to be able to click the button inside the Notification - because it is shown on top and the buttons aren't disabled.

Minimal reproducible example

Main class MyView

public class MyView extends HorizontalLayout {

    Button showModal_button;
    MyDialog dialog;
    MySecondDialog secondDialog;

    public MyView() {
        showModal_button = new Button("show modal");
        dialog = new MyDialog();
        showModal_button.addClickListener(e -> dialog.open());
        add(showModal_button);

        MyNotification noti = new MyNotification();
        dialog.getOpenNotiButton().addClickListener(e -> {
            // user clicked "next/close/whatever" button on dialog
            dialog.close();

            // some business logic on the server which leads to an error/warning/...
            noti.open();

            // fallback to another dialog to fix input errors happend on first dialog
            secondDialog = new MySecondDialog();
            secondDialog.open();

            // now we are stuck as the notification can't be closed anymore while
            // secondDialog is open!

        });

    }

}

class MyDialog

public class MyDialog extends Dialog {

    private Label label = new Label();
    Button open_noti;
    Button close_diag;

    public MyDialog() {
        label.setText("my dialog");

        setCloseOnEsc(false);
        setCloseOnOutsideClick(false);
        close_diag = new Button("close dialog");
        close_diag.addClickListener(e -> close());

        open_noti = new Button("open notification");

        add(label, close_diag, open_noti);
        setHeight("40%");
        setWidth("40%");

    }

    public Button getOpenNotiButton() {
        return open_noti;
    }

}

class MySecondDialog

public class MySecondDialog extends Dialog {

    private Label label = new Label();
    Button open_noti;
    Button close_diag;

    public MySecondDialog() {
        label.setText("my second dialog");

        setCloseOnEsc(false);
        setCloseOnOutsideClick(false);
        close_diag = new Button("close dialog");
        close_diag.addClickListener(e -> close());

        open_noti = new Button("open notification");

        add(label, close_diag, open_noti);
        setHeight("40%");
        setWidth("40%");

    }

    public Button getOpenNotiButton() {
        return open_noti;
    }

}

class MyNotification

public class MyNotification extends Notification {

    public MyNotification() {
        add(new Label("I'm a notification and you can't close me unless you close the dialog behind me!"));
        Button close_button = new Button("close notification");
        close_button.addClickListener(e -> close());
        add(close_button);
        setPosition(Position.MIDDLE);
        setDuration(0);
        addThemeVariants(NotificationVariant.LUMO_PRIMARY);

    }

}

Steps to reproduce

As shown in the GIF. Please use the provided minimal reproducible example: 1) click the button "show modal" -> a modal Dialog opens 2) click the button "open notification" -> the first Dialog disappears, a Notification is opened and a new Dialog is shown 3) try to close the notification by clicking the corresponding button -> can't be closed unless the Dialog is opened.

Environment

Vaadin version(s): 23.1.6 OS: Win10

Browsers

Issue is not browser related

sissbruecker commented 2 years ago

This is due to a feature in Flow called server-side modality. The basic idea is that events from components that have not been added as children to a modal dialog will be ignored. This scenario is definitely problematic though.

As a workaround I see two options:

yuriy-fix commented 2 years ago

@mshabarov , do you think this could be tackled from Flow server-side modality logic?

mshabarov commented 2 years ago

This example uses client-side modality, which is enabled by default for Dialog. The same issue appears when the server-side modality is enabled by UI.addModal(Component). For both options this code should unblock the notification for user interactions:

Notification notification = Notification.show(...);
ElementUtil.setIgnoreParentInert(notification.getElement(), true);

But this is not intuitive at all and a bad DX. I like the idea to make Notification call ElementUtil.setIgnoreParentInert by default, so to make it reachable by default when being opened from dialogs. I'm quite sure that the opposite behaviour (like shown in the video) is NOT desirable for any users: who wants to have an unreachable UI pop-up component when being opened from other modal component... Apart from Notification, I can't come up with any other Vaadin component what may need this, unless it's a custom overlay component not extending Dialog.

yuriy-fix commented 2 years ago

We could consider disabling server-side modality for notifications.