flow-components icon indicating copy to clipboard operation
flow-components copied to clipboard

Dialog won't open after redirect

Open mvysny opened this issue 1 year ago • 2 comments

Description

I have a Spring Security in place which shows LoginRoute when no user is logged in. The LoginRoute is just a simple Div which opens a LoginDialog on attach. The problem is that the dialog won't open in certain cases. More precisely:

  1. The dialog opens when you navigate straight for LoginRoute
  2. The dialog won't open when you navigate to a protected view first, which then redirects to LoginRoute

Debugging the issue I discovered that in Dialog.ensureAttached(), in the second use-case the location change trigger is PROGRAMMATIC, the UI registration listener gets unregistered and the dialog is never attached.

Expected outcome

The dialog should be shown regardless of what kind of navigation chain occurred.

Minimal reproducible example

Create a route which redirects to another route, which then opens a dialog.

Steps to reproduce

I don't have a Spring-Boot+Security project but the issue is easily reproducible in a simpler project:

  1. git clone https://github.com/mvysny/vaadin-simple-security-example
  2. Edit LoginRoute and add the following lines to the constructor:

        final Dialog dlg = new Dialog();
        dlg.setHeaderTitle("Won't be shown");
        dlg.add(new Span("Foo"));
        dlg.setCloseOnOutsideClick(false);
        dlg.open();
  1. Start the app. The app navigates to WelcomeRoute which is protected by security and therefore a redirect to LoginRoute occurs. The LoginRoute tries to open the dialog but the dialog won't open.

This bug is also unit-testable easily.

Environment

Vaadin version(s): 24.3.6 OS: Ubuntu 23.10

Browsers

No response

mvysny avatar Mar 05 '24 08:03 mvysny

Even simpler steps to reproduce: paste this to the Skeleton Starter:

@Route
public class MainView extends VerticalLayout implements BeforeEnterObserver {
    @Override
    public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
        beforeEnterEvent.forwardTo(SecondView.class);
    }

    @Route("second")
    public static class SecondView extends VerticalLayout {
        public SecondView() {
            new Dialog("Foo").open();
            add(new Span("Look Ma, no dialog. Refresh the page to see the dialog"));
        }
    }
}

mvysny avatar Mar 05 '24 08:03 mvysny

Workaround is to add the Dialog manually to the UI:

@Route
public class MainView extends VerticalLayout implements BeforeEnterObserver {
    @Override
    public void beforeEnter(BeforeEnterEvent beforeEnterEvent) {
        beforeEnterEvent.forwardTo(SecondView.class);
    }

    @Route("second")
    public static class SecondView extends VerticalLayout {
        public SecondView() {
            final Dialog dlg = new Dialog("Foo");
            dlg.open();
            UI ui = UI.getCurrent();
            ui.beforeClientResponse(ui, context -> {
                        if (dlg.getElement().getNode().getParent() == null
                                && dlg.isOpened()) {
                            ui.addToModalComponent(dlg);
                            ui.setChildComponentModal(dlg, dlg.isModal());
                        }
                    });
            add(new Span("Look Ma, no dialog. Refresh the page to see the dialog"));
        }
    }
}

I wonder what breaks.... :thinking:

mvysny avatar Mar 05 '24 08:03 mvysny