How to make the reference application more configurable

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?

@gutkowski Distribution dependent OWA which gets its look & styling of the platform it is running on

@ssmusoke I was hoping there’s some other way :slight_smile: I will try to prototype some solution and report it on Talk, when I will come up with something concrete.

hi @gutkowski were you able to make progress on this?

@dkayiwa @wyclif @darius I would like to bring the discussion from this thread Redirecting Link to Create/Find Patient plus View Patient from Legacy UI to Ref App UI here

If I am to add a Register Button to the search page, how do I ensure that it redirects to the correct registration app in my installation?

  • Does App Framework have a registry that can be tapped?
  • I am assuming that there could probably be more than one registration app depending on the location being used (future feature)

Thanks in advance

The redirect URL when the button is clicked just needs to point to the register patient page with the appId parameter value set to your registration appId, an example URL is openmrs/registrationapp/registerPatient.page?appId=referenceapplic2ation.registrationapp.registerPatient which is the default URL in the ref app when you click the Register Patient app, all you need to change is the appId

@wyclif How will the appId change for an implementation that changes the registration app (which is most of them)

When you asked, > how do I ensure that it redirects to the correct registration app in my installation? I assumed you already knew how to customize patient registration and that you had it in place. This page describes how to configure/customize the registration page, under the ‘Initial steps’ subsection on that page, bullet 8 mentions how to set the URL to your customized page, that’s the same URL with the appId that you would redirect to when the button is clicked.

@wyclif Let us step back a bit so that you understand what I am trying to do:

  1. On the Search Widget page I would like to add a Register Patient link. For Reference Application this would point to ~/openmrs/registrationapp/registerPatient.page?appId=referenceapplication.registrationapp.registerPatient

  2. However many implementations override this page with their own custom pages such as ~/openmrs/registrationapp/registerPatient.page?appId=implementation.registerPatient

So my question is: How do I ensure that the Register Link on the search widget can be “easily” configured to point to the correct patient registration url for the implementation

@ssmusoke, so, you want to add a new feature, like “Add a link to the registration app, from within the find patient app” and this requires the system to have a general understanding of “what is the ‘main’ registration app”.

The appframework module does not natively support the idea of “the ‘main’ implementation of something” and the Reference Application doesn’t either. So you’d need to introduce this.

Going back to the first post in this thread, one approach is to replicate what PIH did in introducing a global property for “default patient dashboard”. I don’t like this as a long-term solution if we have to repeat it a lot, but since there’s a precedent for it, and we’ve only been adding one per year, maybe that’s the way to go. It would be straightforward to also introduce a “default registration app” global property and there’s no new design required to implement it like this.

I think the “better” long-term alternative is to explicitly have a way for modules (or system configurations) to register their capabilities (e.g. “registrationapp/registerPatient.page?appId=referenceapplication.registrationapp.registerPatient has the ‘Register Patient’ capability”) and for the implementation to indicate which is its preferred url for each capability. This may be overkill. This could be implemented within the appframework module by using:

  • Extension Points for “Register Patient capability”
  • Extension to say this URL has “Register Patient capability”
  • A new appframework feature to record which is the preferred URL for each capability.

Earlier in this thread, @gutkowski did a bunch of work on enabling “page overrides”. I only just now peeked at this code, and at first glance I’m concerned that this implementation is specifically in the uiframework module, and wouldn’t solve the problem when we’re mixing uiframework-backed and OWA-backed pages. So (I think) this would need to be rewritten if it’s to be the way going forwards. (It may be independently useful on its own for some other use cases.)

So, @ssmusoke, doing the GP thing one more time is sufficient for this use case; there could also be a more design-intensive approach if you want to go that way.

@darius Thank you for the detailed explaination, and I think the way to go is have a GP (defaulting to blank) for now, then looking into a more detailed capability registration mechanism. I will add an EPIC for that in Reference application - targeting 2.7