How to make the reference application more configurable

One of the things i would love to see in the OpenMRS Reference Application, is an increase in configurability. Some one should be able to easily replace an existing page or fragment, in their module, without having to touch a core reference application module. Here is an example of what PIH wanted to do in Haiti: https://issues.openmrs.org/browse/RA-949

From @cioan: Similar to RA-890, we would like to have the ability to overwrite the default visit page. At PIH for the EMR systems in Haiti we have developed a new visit page that replaces the previous coreapps/patientDashboard page. We plan to add new global properties, similar to dashboardUrl to allow implementations to overwrite the visit page.

A response from @darius: I don’t like the idea of proliferating more and more global properties for each “official” page. If we’re going to go down this path, I propose we introduce the idea of a “virtual forwarding page” (or something like that) so that I say I want to go to the “home” page and this results in (1) a lookup in some registry, and (2) a Forward to the configured page. That feels cleaner than having to look up a GP for this.

Any comments? Suggestions or Design insights?

2 Likes

@dkayiwa I do agree with @darius that the GP not the place for such overriding configuration.

Currently we are using using request mappers for overriding pages and fragments - https://wiki.openmrs.org/display/docs/Overriding+Requests+to+Pages+and+Fragments which works seamlessly for many use cases for changing contents of pages/fragments. We extend the controller from the app being overridden but I am not sure this is a best practice, rather than copy and paste to duplicate the contents.

Another area is to handle the app overrides needs to be done in the functionality of the appframework while ensuring the registry has only one active instance of an app type. The simplest example is the registration application referenceapplication.registrationapp.registerPatient which is overridden by implementations. However this app is hard coded in coreapps, the patient dashboard and a couple of other places.

I believe this could be done with something like appframework.getActiveApp(‘referenceapplication.registrationapp.registerPatient’) and a mapping done at run time. So that once an app is overwridden then it is changed in all places - I have over simplified but I hope this makes sense

2 Likes

@dkayiwa bringing this back to the top of the list as its an area I am interested in. Is the Metadata mapping exposure of global properties that @raff & @gutkowski are working on part of this.

No exactly. The goal of this post is mostly to create extension points that do not already exist.

1 Like

@dkayiwa Where can I change or configure the columns that appear on the Patient search page?

Do you mean changing their order or text? By the way, which columns? Or give an example of what you wanna do. :slight_smile:

@dkayiwa I would like to add 2 identifiers at the start of the list, remove the OpenMRS ID that is being shown, and add two more columns at the end of the table. I would also like to update the age column to show months for children below 1 year (Currently it shows a blank)

Not configurable for now. But you can override the patientSearchWidget fragment: https://github.com/openmrs/openmrs-module-coreapps/blob/master/omod/src/main/webapp/fragments/patientsearch/patientSearchWidget.gsp

Have anybody started work on implementing @darius “virtual forwarding page” idea? Or generally, on supporting overriding pages? I would like to do it.

None has implemented it. Thanks @gutkowski for taking this up! :slight_smile:

Okay, I will ask you for thoughts when I’ll prepare some design :wink:
I’ve created issue https://issues.openmrs.org/browse/RA-1212 but I don’t have permissions to change its status.

1 Like

I have some ideas, but I need a bit more information on target use cases, and I have some doubts about design.

So, I would replace PageRequestMapper and FragmentRequestMapper for simple overrides with annotations, let’s temporarely call them PageOverride and FragmentOverride. When module developer would want to override some page, he would need to annotate specific controller and pass required information about overriden page to annotation.

It is quite similiar to current solution, but has one big advantage: information about override is static, it could be easily displayed in UI, so system administrator would be able to enable/disable overrides or choose one of them if there’s more than one for specific page/fragment(I think this case needs some way to set default order of override). It could be part of Manage Apps view.

There’s one more question: do we need to be able to override RequestMapping’s as well? By default Spring doesn’t allow binding more than one handler to single url, but we could introduce our own RequestMapping-like annotation and handle it with custom HandlerMapping by extending AbstractHandlerMapping. This solution would require replacing RequestMapping annotations in existing codebase. I would rather stay away from it, if we don’t have any important use cases.

2 Likes

It seems nobody has any suggestions, I will start work on implementing described idea.

I’m still waiting for your thoughts about need of overriding URL mappings :slight_smile:

@gutkowski, thanks for picking it up! Seeing a usage example of the annotation would help to provide feedback. It would be nice to be able to set a priority programmatically as well.

Providing custom HandlerMapping sounds like a good approach for providing overrides for any request (not only specific to UI framework). I don’t think it requires replacing RequestMapping annotations though. Please see for example https://www.mkyong.com/spring-mvc/configure-the-handler-mapping-priority-in-spring-mvc/ It seems that it would be enough to have a handler mapping with a very high priority, which contributes resolved overrides. You would only have to implement the code for resolving overrides, which could be defined via annotations.

@gutkowski am in agreement with Rafal. I look forward to seeing a pull request. :slight_smile:

@raff, @dkayiwa I did some prototyping today, after introducing changes in UiFramework I’m able to override any page with annotation:

package org.openmrs.module.override.page.controller;

import org.openmrs.ui.framework.annotation.OverridePage;

@OverridePage(providerName = "adminui", pageName = "metadata/configureMetadata")
public class FakePageController {}

This example overrides Configure Metadata page. This internally redirects request to override/fake.page.

It would be nice to be able to set a priority programmatically as well

I agree, that would be handy.

Thank you for advice about HandlerMapping. This solution is way better!

Thanks @gutkowski for looking into this. Do you plan to create a pull request? :slight_smile:

Yes, I do, but I didn’t finish yet. I can open PR just to show current state of work if you would like to review it.

Oh i see! Do not worry. Create it when you are ready. Thanks again for the great work! :slight_smile:

I’m sorry it took so long, but I’ve opened inital PR, it is backend only: https://github.com/openmrs/openmrs-module-uiframework/pull/41

I have a little problem: as I mentioned, I wanted to provide UI for administrators to view and manage overrides. Considering the fact, that uiframework module is distribution independent, how should it look like? I guess uiframework should not rely on any distribution’s styling, but it would look bad if it would have totally different look. I don’t know how exactly approach this issue. Are there any proven best practices?