Adding a Dashboard to root application screen with top menu

Hi team,

I’ve just created a dashboard, following the “Dashboards add-on video tutorial”, but I don’t know to add the dashboard to the root application screen with top menu.
I don’t know how to open the main screen window descriptor, to find where to add the xmlns:dashboard namespace or where to find the main:workArea tag to put the created dashboard.

I’d bee very grateful to receive any ideas to achieve the goal.

Thanks in advance

Hello,

here is my solution, which I always use:

The goal is to keep a dashboard tab always open. The dashboard itself is a normal screen.

Dashboard.java
In the method onAfterClose I open the dashboard again when it has been closed by ‘Close All’.

@UiController("ksm_Dashboard")
@UiDescriptor("dashboard.xml")
public class Dashboard extends Screen {

    @Inject
    private Screens screens;
    
    @Subscribe
    public void onAfterClose(AfterCloseEvent event) {
        SideMenu sideMenu = findSideMenu();
        if (sideMenu != null) {
            final SideMenu.MenuItem dashboardMenuItem = sideMenu.getMenuItem("ksm_Dashboard");
            if (dashboardMenuItem != null) {

                // Aktuellen WindowStack merken
                Screens.WindowStack selectedWindowStack = screens.getOpenedScreens().getWorkAreaStacks().stream()
                        .filter(Screens.WindowStack::isSelected)
                        .filter(windowStack -> windowStack.getBreadcrumbs().stream().noneMatch(screen -> screen instanceof Dashboard))
                        .findAny()
                        .orElse(null);

                // wieder öffnen
                dashboardMenuItem.getCommand().accept(dashboardMenuItem);

                // Aktuellen WindowStack wieder aktivieren
                if (selectedWindowStack != null) {
                    selectedWindowStack.select();
                }

            }
        }
    }

    /**
     * Sucht das SideMenu im Top-Level-Window oder alternativ in der Host-Screen, falls das TopLevelWindow null ist.
     * Dies ist der Falls, wenn man das Fragment in die MainScreen einbindet.
     *
     * @return sidemenu oder null, wenn es nicht gefunden wurde
     */
    private SideMenu findSideMenu() {
        Window window = AppUI.getCurrent().getTopLevelWindow();
        if (window == null) {
            window = getWindow();
        }
        if (window != null) {
            return window.getComponents().stream()
                    .filter(component -> component instanceof SideMenu)
                    .map(component -> (SideMenu) component)
                    .findAny()
                    .orElse(null);
        } else {
            return null;
        }
    }

}

ExtMainScreen.java
Here I overwrite the menu entry for the dashboard, so that instead of showing a new dashboard, it opens the existing one. Also for me to add a listener to the WorkArea to open the dashboard in initial state.

@UiController("extMainScreen")
@UiDescriptor("ext-main-screen.xml")
public class ExtMainScreen extends MainScreen {

    ...

    @Subscribe
    public void onInit(InitEvent event) {
        // Dashboard-Tab öffnen, wenn alle anderne Tabs geschlossen sind
        final SideMenu.MenuItem dashboardMenuItem = sideMenu.getMenuItem("ksm_Dashboard");
        if (workArea instanceof WebAppWorkArea && dashboardMenuItem != null) {

            workArea.addStateChangeListener(stateChangeEvent -> {
                if (stateChangeEvent.getState() == INITIAL_LAYOUT) {
                    screenBuilders.screen(this)
                            .withScreenClass(Dashboard.class)
                            .show();
                }
            });

            // Verhindern, dass das Dashbord doppelt geöffnet wird
            final Consumer<SideMenu.MenuItem> dashboardMenuItemCommand = dashboardMenuItem.getCommand();
            dashboardMenuItem.setCommand(menuItem -> {

                screens.getOpenedScreens().getWorkAreaStacks().stream()
                        .filter(windowStack -> windowStack.getBreadcrumbs().stream().anyMatch(screen -> screen instanceof Dashboard))
                        .peek(Screens.WindowStack::select)
                        .flatMap(windowStack -> windowStack.getBreadcrumbs().stream())
                        .filter(screen -> !(screen instanceof Dashboard))
                        .forEach(Screen::closeWithDefaultAction);

                if (screens.getOpenedScreens().getWorkAreaScreens().stream().noneMatch(screen -> screen instanceof Dashboard)) {
                    dashboardMenuItemCommand.accept(dashboardMenuItem);
                }

            });
        }
    }

    @Subscribe
    public void onAfterShow1(AfterShowEvent event) {
        // Dashboard öffnen. Hinweis: die App-Property "cuba.web.defaultScreenId" kann nicht verwendet werden
        // weil z.B. der Revisor keinen Zugriff auf das Dashboard hat. Daher wird das Dashboard manuell geöffnet.
        final SideMenu.MenuItem dashboardMenuItem = sideMenu.getMenuItem("ksm_Dashboard");
        if (dashboardMenuItem != null) {
            dashboardMenuItem.getCommand().accept(dashboardMenuItem);
        }
    }

}

I hope this is useful for you.

Greetings
Andreas

2 Likes

Thanks, Andreas, for your example and explanation. I’ll try to adapt your solution in my project althought my dashboard class extends from ScreenFragment instead of from Screen like in your case.

I’m very grateful for your support.

Greetings.