vaadin-component-factory / idle-notification

Display a notification and actions to the user before session-timeout
Apache License 2.0
2 stars 9 forks source link

Add support for multiple UIs #16

Open stefanuebe opened 6 months ago

stefanuebe commented 6 months ago

At the moment the addon seems not to support multiple UIs.

In a simple use case, where an additional UI is opened at some point in the future, the instances of the idle notification are async. This means, that for the earlier opened UI the idle notification will popup, while for the other UI it is not shown.

Also any actions in one UI are not reflected in the other UIs. If UI 1 is interacted with, UI 2 is not informed and thus still thinks, that it's session is running out.

stefanuebe commented 5 months ago

Side note: Using server side push brought up different issues where one is, that on each single request all other UIs get "pushed" all the time, which may lead to unnecessary overhead. Also having long term operations blocking one UI may lead to async issues regarding the timer.

Therefore I used the client side BroadcastChannel to communicate between the tabs directly. Here is a workaround sample:

frontend/scripts/idle.js

window.Vaadin.Flow._setupIdleSync = (idleElement) => {
    const broadcast = new BroadcastChannel("idle-notification");

    const h = idleElement._handleLoad;
    idleElement._handleLoad = (currRequest) => {
        h.call(idleElement, currRequest);

        if (
            currRequest.status === 200 &&
            !idleElement._displayProcessStarted &&
            idleElement._isVaadinRequest(currRequest)
        ) {
            broadcast.postMessage("ping");
        }
    }

    broadcast.addEventListener("message", e => {
        idleElement._resetTimer();
        if(idleElement.opened)
            idleElement.opened = false;
    });
}

Your service init listener with an UI init event.

@JsModule("./scripts/idle.js")
public class MyServiceInit implements VaadinServiceInitListener {
    @Override
    public void serviceInit(ServiceInitEvent event) {
        VaadinService source = event.getSource();
        source.addUIInitListener(initEvent -> {
            // ... setup idle notification

            // apply fix
            idleNotification.getElement().executeJs("window.Vaadin.Flow._setupIdleSync(this)");
        });
    }
}