jmix-framework / jmix

Jmix framework
https://www.jmix.io
Apache License 2.0
684 stars 123 forks source link

Support for Tabbed Window mode #2154

Open glebfox opened 1 year ago

glebfox commented 1 year ago

Goal: similar to Classic UI, View are opened in the separate tabs.

Due to impossibility to alter Vaadin behaviour, routing seems impossible. But some kind of link handling is needed to open a view by a link.

Seems that, separate MainView template that contains TabSheet is needed.

ericraskin commented 11 months ago

+1 for this. I have a few applications that rely on this feature extensively. My users open up multiple entities at the same time to visually compare them, which is hard to do when there is only one window at a time. Also, while working on an entity, a user can open another one temporarily to handle a request and then go back to what they were doing. They also multi-task between entities (jobs in our system), working on more than one at a time and flipping back and forth to view status as the jobs run.

Lack of this feature is keeping us on Cuba Platform for the moment. I hope you will consider pushing the priority up and implementing this sooner rather than later.

BryanYin commented 9 months ago

Got few inquiries about this feature too...

1078618113 commented 9 months ago

I hope the official can launch this function as soon as possible. After getting used to using the Tab function of 1.x, it is very inconvenient that there is no such function in 2.x.

kkwoop commented 9 months ago

I urgently need this functionality, please follow up as soon as possible. Thank you very much.

wanchoonkit commented 7 months ago

I hope this feature can be ready soon. We need it to migrate our customer to Jmix

zhaojc commented 6 months ago

it is very usefull feature.please support it as soon as possiable.thanks

cklee1967 commented 4 months ago

We have a big development on Cuba which relies on Tabbed Windows, used by Financial Services customers. The Tabbed Windows is a key selling point. And our large development team are still waiting for this feature before we start the migration to Cuba. We need this in Jmix as soon as possible.

Peach185 commented 4 months ago

Really hope that the development of this can be escalated. Hands down one of the most unique and loved feature available while developing in CUBA 🙌

jon-m-craig commented 4 months ago

This capability is utterly vital, foundational, to how our application works. Users must be able to open multiple screens. For example, users will have open the Patient screen with a particular patient pulled up. They need to be able to for example open the Scheduler to schedule an appointment for that patient, or go to the detail of a particular invoice for that patient, and switch back and forth. This is absolutely needed! Our users don't care one bit for the ability to have "deep linking"/"friendly URLs" for linking. They need the multiple screens open!

knstvk commented 4 months ago

Thank you all for your feedback. We will consider moving this feature to the next release in October 2024.

glebfox commented 1 month ago

Hello everyone!

I want to inform you about the current state and problems with the implementation. Unfortunately, Tabbed Window mode won't be included into the October 2024 release. Below is a detailed explanation of the problems:

1. There is no single point of navigation handling.

The Vaadin doc says:

If you want to manually handle navigation events, you can replace it by setting a handler for navigation events using history.setHistoryStateChangeHandler(HistoryStateChangeHandler).

The problem is that if I set a custom HistoryStateChangeHandler when the UI is just initialized, the handler is overwritten by the internal logic of the UI class.

The following code overwrites previously set HistoryStateChangeHandler: flow/flow-server/src/main/java/com/vaadin/flow/component/UI.java at main · vaadin/flow · GitHub

if (firstNavigation) {
    firstNavigation = false;
    getPage().getHistory().setHistoryStateChangeHandler( // <1>
            e -> renderViewForRoute(e.getLocation(), e.getTrigger()));

    if (getInternals().getActiveRouterTargetsChain().isEmpty()) {
        // Render the route unless it was rendered eagerly
        renderViewForRoute(location, navigationTrigger); // <2>
    }
}

1 - Overwrites HistoryStateChangeHandler 2 - Uses internal logic regardless HistoryStateChangeHandler

So the only way to override User Navigation handling is to override the UI class, which is also challenging.

  1. com.vaadin.flow.server.communication.JavaScriptBootstrapHandler#createAndInitUI ignores passed UI class and creates com.vaadin.flow.component.UI
  2. Public BrowserLeaveNavigationEvent class doesn’t have public getters.

Also, programmatic navigation (UI.navigate(...)) delegates to different implementations, e.g.: com.vaadin.flow.component.UI#handleNavigation and com.vaadin.flow.router.Router#navigate() which use different implementations of com.vaadin.flow.router.NavigationHandler.

These problems are not show-stoppers, but they require extra code copying/pasting and investigation of other places that may handle navigation to override them.

2. Preserve on refresh

In Classic UI, @PreserveOnRefresh is used on the UI class, so each time users refresh a page, they get the same UI instance and thus the same instances of the UI Scope beans.

Vaadin 10 and later don’t preserve the UI instance between refreshes. The @PreserveOnRefresh must be placed in a component class that’s a route target , i.e. a view.

Another limitation is that the component persists only if the URL remains the same. This means that, even if the URL query parameters change and the page is refreshed, new instances of the opened views are created.

Currently, the inability to persist UI state regardless of URL changes is one of the show-stoppers.

3. Existing view opening API

Initially, the view opening APIs (ViewNavigators and DialogWindows) were designed to reflect differences in the opening process. For example, when users navigate to a view, they cannot access it until it's fully opened and attached to the UI. Thus, it's impossible to have an open listener or a view configurer API, but they are available if a view is opened in a dialog. This differs from the Classic UI where there is a single ScreenBuilders API with an openMode setting.

By implementing Tabbed Window mode, we need to provide a single view opening API again, e.g.ViewBuilders, and provide conversion between ViewNavigators/DialogWindows and ViewBuilders which requires more time and careful testing.