Cannot set the locale for the initial ExtMainScreen and SideMenu for an Anonymous user before he/she logs in

Hello Everyone

I have found a situation, that I believe needs improvement.

Operating System: macOS Big Sur 11.1
Browser: Safari Version 14.0.2 (16610.3.7.1.9)
File System: Case-Sensitive Journaled HFS+ (APFS)
Datebase: MySQL 8.0.19

CUBA Platform version: 7.2.11
CUBA Studio plugin version: 14.3-193
IntelliJ version: CUBA Studio 2019.3

Use Case: I need to present an Anonymous user with the possibility to change the locale before the Login dialog is displayed.

My application presents the Anonymous user with a SideMenu and an initial ExtMainScreen (analog to the cuba-petclinic-social-login-master demo). The ExtMainScreen currently contains a BrowserFrame that displays my static HTML pages that are stored in a resource path and the http://localhost:8080/app/VAADIN directory as described in the documentation at https://doc.cuba-platform.com/manual-7.2/static_resources.html.

The Anonymous user must be able to select his/her locale before opening the Login dialog (that contains the locale lookup field) so that the SideMenu changes its language immediately and so that I can also load the proper language-dependent static HTML page(s) into the BrowserFrame at the same time, thereby synchronized with the SideMenu language. Any other UI components in the ExtMainScreen should also receive their new language.

Problem: I can allow access to the SettingsWindow for the Anonymous user but the SettingsWindow.java code automatically disables the language “appLangField” if “cuba.localeSelectVisible = true” in web-app.properties for the Login dialog. Here is the code:

    boolean langFieldVisible = !globalConfig.getLocaleSelectVisible();
    languageLabel.setVisible(langFieldVisible);
    appLangField.setVisible(langFieldVisible);

Please see: https://github.com/cuba-platform/cuba/blob/a9f54fbbf4cb9a381fe6ce38c5d44c5326d6694f/modules/web/src/com/haulmont/cuba/web/app/ui/core/settings/SettingsWindow.java

Therefore, an Anonymous user can only change his locale in the Login dialog when logging into the application but not beforehand and not afterward either; after the Anonymous user has logged in, the langFieldVisible is still not visible.

My workaround for this is situation is the following:

public class ExtSettingsWindow extends SettingsWindow {

@Inject
private Screens screens;
@Inject
private DefaultApp defaultApp;

@Override
public void init(Map<String, Object> params) {
    super.init(params);

    languageLabel.setVisible(true);
    appLangField.setVisible(true);
    appLangField.setNullOptionVisible(false);
    appLangField.addValueChangeListener(e -> {
        defaultApp.setLocale(LocaleUtils.toLocale(appLangField.getValue()));
    });

    okBtn.addClickListener(e -> {
        screens.create(ExtMainScreen.class, OpenMode.ROOT).show();
    });
}

}

This workaround allows the Anonymous user to set the locale and also reload my main screen, thereby updating the SideMenu and my static HTML page dependent upon the locale during the ExtMainScreen init(), all before opening the Login dialog. And once the user has logged in, it allows the user to update the SideMenu and everything else without logging out and back in. In the default implementation, without the Anonymous user access enabled, the user can set the locale but this does not update the language anywhere; a new login is required.

(Maybe I should have used the “cuba.web.initialScreenId” instead of hardcoding the screen class.) Anyway…

In my opinion, this is a normal use case and should not require such a workaround. An Anonymous user must be able to change the locale before logging into the application. My voodoo should not be necessary.

Can you please consider improving this implementation?

In a final note, while I was looking into different ways of refreshing my ExtMainScreen I found this bit of documentation that I’m sure is incorrect…

https://doc.cuba-platform.com/manual-7.2/webBrowserTools.html

webBrowserTools.showWebPage(“https://cuba-platform.com”, ParamsMap.of("_target", “blank"));

should be…

webBrowserTools.showWebPage(“https://cuba-platform.com”, ParamsMap.of(“target”, “_blank"));

as is discussed in this post:

I hope that all of this information can be of help to everyone.

Best regards
Chris

Hi,

You’re probably right but the thing is that in order to change locale you need to reload the app so the new locale is fetched and all components update their value, therefore, the data can be lost. Because of that, the current implementation requires a user either to re-login or select a locale before login, so we can be sure that no data will be lost.

In case of Anonymous access, when available only read-only screens, e.g. some welcome screen, there is no problem in reloading the entire app, therefore, It can be easily implemented with minimal effort.

I wouldn’t recommend giving an anonymous user access to the settings screen, because it has much more settings than an anonymous user needs, instead, I’d recommend extending the main screen and add a locale selector to it, e.g.:

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

    @Inject
    private LookupField<Locale> localeSelect;

    @Inject
    private GlobalConfig globalConfig;
    @Inject
    private DefaultApp app;

    @Subscribe
    protected void onInit(InitEvent event) {
        initLocales();
    }

    private void initLocales() {
        boolean authenticated = app.getConnection().isAuthenticated();
        localeSelect.setVisible(!authenticated);

        if (!authenticated) {
            localeSelect.setOptionsMap(globalConfig.getAvailableLocales());
            localeSelect.setValue(app.getLocale());

            boolean localeSelectVisible = globalConfig.getLocaleSelectVisible();
            localeSelect.setVisible(localeSelectVisible);

            localeSelect.addValueChangeListener(e -> {
                Locale selectedLocale = e.getValue();

                if (selectedLocale != null) {
                    app.setLocale(selectedLocale);
                    app.createTopLevelWindow();
                }
            });
        }
    }
}

Screenshot 2021-01-18 at 12.50.33

Demo project: anonymous-screens-access.zip (91.4 KB)

Regards,
Gleb

1 Like

Hi Gleb

Thank you very much for the quick response and your efforts. Your solution works great! I had already tried something very similar to this, my Lookupfield was in the WorkArea directly above my BrowserFrame and not the SideMenu, but I thought that it would better not to have three different places for the locale selection: Settings, Login Dialog and SideMenu/WorkArea. That’s why I tried the Settings screen implementation. Your solution is a definite improvement on my first and second ideas, so I’m very happy with it. Now I just need to match the Lookfield’s style with the rest of the SideMenu , but I will look into that sometime later.

Just a note, I had to make two minor changes to your code because it would not compile for me.

I replaced…

Locale selectedLocale = e.getValue();

with …

Locale selectedLocale = (Locale) ((HasValue.ValueChangeEvent) e).getValue();

and I also had to inject “defaultApp” instead of “app”.

Therefore, this problem is solved for me. Thanks again.

Best regards
Chris

As my code shows I use the following injections:

@Inject
private LookupField<Locale> localeSelect; (1)

@Inject
private DefaultApp app; (2)
  1. I use LookupField with type as a result e.getValue() returns correct value type
  2. Injected field can have any name

Regards,
Gleb

I suppose that predefined borderless and align-center styles can suit you:

stylename="borderless align-center"

Screenshot 2021-01-19 at 11.01.46

Hi Gleb

Thank you once again! I had never considered that I could/should modify the injected variables, so I did not pay close enough attention to that. My failure. I appreciate you educating me on this.

This style setting is also perfect. Everything looks great.

By the way, while setting the new style, I found a bug in the Studio. My fragment properties are automatically removed when I modify any of the other component attributes, e.g. editable, visible. I will open a new ticket for this with a complete description as soon as possible.

Best regards
Chris