Supporting "old" UI and "new" UI (uiframework) in the same module

As OpenHMIS team we thought that it would be a good idea to support both types of UIs as they are currently used together in one module rather than creating a separate UI module for the new UI.

Basically what we did to be able to run our module with both types of UIs (“old” one using OpenMRS 1.9.9 and new one using OpenMRS 2.2 (with 1.11.3)) is the following steps:

  1. Getting rid of the uiframework bean definition in webModuleApplicationContext.xml. Instead we defined a configuration class that would only create the bean if the uiframework module is loaded.

    package org.openmrs.module.openhmis.inventory.uiframwork;

    import org.openmrs.annotation.OpenmrsProfile; import org.openmrs.ui.framework.StandardModuleUiConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;

    @Configuration @OpenmrsProfile(modules = { “uiframework:.” }) public class UiConfigurationInventory {

     @Bean
     public StandardModuleUiConfiguration createUiConfigurationBean() {
             StandardModuleUiConfiguration standardModuleUiConfiguration = new StandardModuleUiConfiguration();
             standardModuleUiConfiguration.setModuleId("openhmis.inventory");
             return standardModuleUiConfiguration;
     }
    

    }

  2. adding @OpenmrsProfile(modules = { "uiframework:*.*" }) to our controllers for the new UI to make sure the controller actions are only applied if the uiframework module is present. As our controllers at this stage are pretty basic that looks like this:

    package org.openmrs.module.openhmis.inventory.page.controller;

    import java.io.IOException; import java.util.List;

    import org.openmrs.module.appframework.domain.Extension; import org.openmrs.module.appframework.service.AppFrameworkService; import org.openmrs.module.openhmis.inventory.web.ModuleWebConstants; import org.openmrs.ui.framework.UiUtils; import org.openmrs.ui.framework.annotation.SpringBean; import org.openmrs.ui.framework.page.PageModel; import org.openmrs.ui.framework.page.PageRequest; import org.springframework.stereotype.Controller; import org.openmrs.annotation.OpenmrsProfile;

    @Controller @OpenmrsProfile(modules = { “uiframework:.” }) public class InventoryLandingPageController {

    public void get(PageModel model, @SpringBean("appFrameworkService") AppFrameworkService appFrameworkService,
            PageRequest request, UiUtils ui) throws IOException {
        List<Extension> extensions = appFrameworkService.getExtensionsForCurrentUser(ModuleWebConstants.LANDING_PAGE_EXTENSION_POINT_ID);
        model.addAttribute("extensions", extensions);
    }
    

    }

My question now is if this approach is a good way to go, or if we are violating any rules (if there are any…) concerning best practice to provide the new UI to our modules. As far as I can see pretty much everything concerning the new UI is done in separate modules and I wonder if I might miss something important if I don’t follow that pattern.

Opinions please :slight_smile: Good idea?/bad idea?/missing something important?

Edit: I forgot to mention (as Rafal is pointing out) that we are having the following lines in our config.xml:

<aware_of_module version="3.3.1">org.openmrs.module.uiframework</aware_of_module>
<aware_of_module version="2.3">org.openmrs.module.appframework</aware_of_module>
<aware_of_module version="2.2">org.openmrs.module.providermanagement</aware_of_module>
<aware_of_module version="1.6">org.openmrs.module.uicommons</aware_of_module>

P.S. Here’s a link to the commit that I made to achive running both UI types in one module. Just in case people are interested in details…

2 Likes

I like what you did!

I don’t see it in your commit, but you also added dependencies to appframework, uicommons and configured uiframework, appframework, uicommons as aware of dependencies in config.xml, which is needed for this to work.

I would love to see your approach being documented as one of possibilities on a wiki. Maybe somewhere close to https://wiki.openmrs.org/x/K46UAw (child or sibling page?)

I personally cannot think of a better way of doing it other than what you have, if the OpenMRS versions you are supporting have the OpenmrsProfile class implemented (1.7.5, 1.8.5, 1.9.8, 1.10, and later) And i also like maintaining one module to support both the legacy and refapp UIs.

My scenario was a bit tricky as i still had to support a good number of implementations using the xforms module on 1.6, which does not have the OpenmrsProfile class. So i ended up doing this commit:

In summary, i created a bean, which i registered in my webModuleApplicationContext.xml as: This bean registers the org.openmrs.ui.framework.StandardModuleUiConfiguration at runtime, if the module is running under the reference application.

Thanks @raff and @dkayiwa four your input.

I created a page in the wiki for that.

https://wiki.openmrs.org/display/docs/Support+old+and+new+UI+in+one+module

I’m not sure if this is the right spot for it, so everybody feel free to move it somewhere else or so. Also feel free to add and/or edit…

2 Likes

@mario, thank you so much for setting up the documentation and the good spirit of sharing. Please keep it up! :slight_smile:

As fur am time curious about UI framework this class org.openmrs.ui.framework.StandardModuleUiConfiguration configured as bean in webApplicationContext.xml file loads the fragmentControllers to the legacyui homepage in the referenceApplication, am trying to learn uiframework in details, is it the case .cc.@dkayiwa @mozzy