Ui.springmvc module

Overview

The ui.springmvc module allows you to rapidly compose new UIs out of re-usable components.

In order to use this module you would write another module that depends on it, and configures the way it wants to use the ui.springmvc's widgets via it's webModuleApplicationContext.xml.

The goal of this module is to make development and reuse of widgets quick and easy, without changing OpenMRS's underlying MVC paradigms. (The module's code does not intend to be elegant.)

Additional widgets are most welcome.

Available Components

Homepage with list of "Apps"

<bean id="rwandamohHomepage" class="org.openmrs.module.ui.springmvc.web.HomepageController">
    <property name="logoUrl" value="/moduleResources/rwandamoh/images/rwanda300.png"/>
</bean>

"App" with an icon and a homepage

<bean id="dataentryApp" class="org.openmrs.module.ui.springmvc.App">
    <property name="parentHomepageUrl" value="/module/rwandamoh/homepage.form"/>
    <property name="name" value="HIV Flowsheet"/>
    <property name="homepageUrl" value="/module/rwandamoh/dataentry/homepage.form"/>
    <property name="iconFilename" value="/moduleResources/ui/springmvc/images/application64.png"/>
</bean>

Create Patient page

<bean id="dataentryCreatePatientController" class="org.openmrs.module.ui.springmvc.web.dataentry.CreatePatientController">
    <property name="returnUrl" value="/module/rwandamoh/dataentry/patient.form"/>
    <property name="app"><ref local="dataentryApp"/></property>
</bean>

Patient Dashboard with Tabs, each containing Widgets

<bean id="dataentryPatientDashboard" class="org.openmrs.module.ui.springmvc.web.PatientDashboardController">
    <property name="app"><ref local="dataentryApp"/></property>
    <property name="config">
        <bean class="org.openmrs.module.ui.springmvc.web.DashboardConfiguration">
            <property name="tabs">
                <list>
                    ...
                </list>
            </property>
        </bean>
    </property>
</bean>

Available Widgets

"Anywhere" Widgets

Patient Search Widget

An AJAX find-patient widget.

onClickUrl (required): what url to go to go to when a patient is clicked on. (will have "?patientId=xyz" appended)

Patient Viewed History Widget

Shows a list of the patients the current user has viewed during this session

onClickUrl (required): where to go when a patient is clicked on. (will have "?patientId=xyz" appended)
maxSize (default=10): maximum number of patients to show in the list

Button Widget

A button

label (required): the text on the button
href: what url to go to when clicked

Patient Widgets

These widgets are only usable in a patient-centric context, like on a patient dashboard

Program Enrollment Widget

Allows you to enroll the patient in, and exit them from a specific program. You may specify an html forms to use to enroll the patient, otherwise a generic date + workflow-statuses will be used.

programId (int, required): what program is this for
showPastEnrollments (boolean, default=true): whether to show a compact list of past enrollments in the program
showCurrentEnrollment (boolean, default=true): whether to show details of the current program enrollment
showEnrollButton (boolean, default=true): whether to allow enrollment (if the patient isn't already enrolled)
showExitButton (boolean, default=true): whether to allow exiting (if the patient is currently enrolled)
enrollmentFormIds (List<Integer>): ids of forms that may be used to enroll the patient
outcomeWorkflowIds (List<Integer>): ids of workflows that must have a value specified when the patient is exited from the program.

Form Table Widget

Shows one-row-per-encounter, based on a form or an encounter type, and lets you add more via an html form.

encounterTypeId (int): only show encounters of this encounter type
formId (int): only show encounters for the given form
addAnotherFormId (int): if specified then an "Add another" button will be displayed, popping up this html form.
columns (List<Column>, required): what columns to display in this table. (See Utility classes -> Columns below.)

Obs Group Table Widget

Shows one-row-per-obs-group

groupingConceptId (int, required): show obs groups with this as their grouping concept
columnConceptIds (LinkedHashMap<String, Integer>, required): text of the column heading, and the id of the concept to display in that column
addAnotherFormId (int): if specified, display an "Add another" button that pops up this html form

Obs Graph Widget

Shows a graph (over time) of numeric obs of the specified concept

conceptId (int, required): which concept
minY (int): optional min value of the y-axis
maxY (int): optional max value of the y-axis

Active Problems Widget

A simple list of active problems for a patient, e.g. what you'd get if you integrate across PROBLEM ADDED and PROBLEM REMOVED obs for a patient.

addConceptId (int, required): what concept adds problems to the list
removeConceptId (int): what concept removes problems from the list
showCurrentProblems (boolean, default=true): whether to show currently-active problems
showResolvedProblems(boolean, default=false): whether to show problems that have been resolved

Regimen Widget

Shows a regimen view of drugs orders whose generic drug is in the specified drug set

drugSetConceptId (int, required): which concept represents the drug set (e.g. antiretroviral drugs)
regimenSuggestions (List<RegimenSuggestion>): regimens that may be added via shortcuts
changeReasonConceptIds (LinkedHashMap<Integer, String>): reasons that may be given for changing a regimen (concept -> display label)

Visit List Widget

A widget that shows all the patient's visits, where a visit is defined as all encounters at the same location on the same day

maxNumber (int): optional limit for how many to show
sortDescending (boolean, default=true): if true, show the most-recent at the top

Utility classes

Columns

SingleConceptColumn

conceptId (int, required): just this concept

Column

String heading
List<DisplayItem> contents

TextDisplayItem

String html

ConceptDisplayItem

Integer conceptId

Download

Screenshots

Overall homepage

App homepage

Patient dashboard

Release Notes

Version 0.1

  • Initial alpha release

Basic Example

This would be the webModuleApplicationContext.xml file for a simple module that uses ui.springmvc to create one app. It uses the patient search widget, the recently-viewed-history widget, and the create-patient page. It also includes a patient dashboard with a few tabs

<?xml version="1.0" encoding="UTF-8"?>
  
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-2.5.xsd
           http://www.springframework.org/schema/util
           http://www.springframework.org/schema/util/spring-util-2.0.xsd">
    
    <!-- Set up URL mappings because we need to control how our pages link together -->
    <bean id="rwandamohUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="order"><value>50</value></property>
        <property name="mappings">
            <props>
                <prop key="module/rwandamoh/homepage.form">rwandamohHomepage</prop>
                <prop key="module/rwandamoh/dataentry/homepage.form">dataentryHomepage</prop>
                <prop key="module/rwandamoh/dataentry/patient.form">dataentryPatientDashboard</prop>
                <prop key="module/rwandamoh/dataentry/createPatient.form">dataentryCreatePatientController</prop>
            </props>
        </property>
    </bean>    
    
    <!-- this is our overall homepage, which will include links to all apps -->
    <bean id="rwandamohHomepage" class="org.openmrs.module.ui.springmvc.web.HomepageController">
        <property name="logoUrl" value="/moduleResources/rwandamoh/images/rwanda300.png"/>
    </bean>

    <!-- this is our create patient page -->    
    <bean id="dataentryCreatePatientController" class="org.openmrs.module.ui.springmvc.web.dataentry.CreatePatientController">
        <property name="returnUrl" value="/module/rwandamoh/dataentry/patient.form"/>
        <property name="app"><ref local="dataentryApp"/></property>
    </bean>

    <!-- this is the homepage for our main app, which includes a few widgets. The app itself is defined below -->
    <bean id="dataentryHomepage" class="org.openmrs.module.ui.springmvc.web.AppHomepageController">
        <property name="app"><ref local="dataentryApp"/></property>
        <property name="widgets">
            <list>
                <bean class="org.openmrs.module.ui.springmvc.web.widget.PatientSearchWidget">
                    <property name="onClickUrl" value="/module/rwandamoh/dataentry/patient.form"/>
                </bean>
                <bean class="org.openmrs.module.ui.springmvc.web.widget.ButtonWidget">
                    <property name="label" value="Create Patient"/>
                    <property name="href" value="/module/rwandamoh/dataentry/createPatient.form"/>
                </bean>
                <bean class="org.openmrs.module.ui.springmvc.web.widget.PatientViewedHistoryWidget">
                    <property name="onClickUrl" value="/module/rwandamoh/dataentry/patient.form"/>
                    <property name="maxSize" value="10"/>
                </bean>
            </list>
        </property>
    </bean>

    <!-- this is our patient dashboard, with a few tabs -->
    <bean id="dataentryPatientDashboard" class="org.openmrs.module.ui.springmvc.web.PatientDashboardController">
        <property name="app"><ref local="dataentryApp"/></property>
        <property name="config">
            <bean class="org.openmrs.module.ui.springmvc.web.DashboardConfiguration">
                <property name="tabs">
                    <list>
                        <bean class="org.openmrs.module.ui.springmvc.web.TabConfiguration">
                            <property name="key" value="demographics"/>
                            <property name="label" value="rwandamoh.demographics.title"/>
                            <property name="contents">
                                <list>
                                    <bean class="org.openmrs.module.ui.springmvc.web.widget.ImportUrlWidget">
                                        <property name="url" value="/module/ui/springmvc/widget/demographicsWidget.form"/>
                                    </bean>
                                    <bean class="org.openmrs.module.ui.springmvc.web.widget.ProgramEnrollmentWidget">
                                        <property name="title" value="HIV Program Enrollment"/>
                                        <property name="programId" value="1"/>
                                        <property name="outcomeWorkflowIds">
                                            <list>
                                                <value>1</value>
                                            </list>
                                        </property>
                                        <property name="enrollmentFormIds">
                                            <list>
                                                <value>2</value>
                                            </list>
                                        </property>
                                    </bean>
                                </list>
                            </property>
                        </bean>
                        <bean class="org.openmrs.module.ui.springmvc.web.TabConfiguration">
                            <property name="key" value="medhistory"/>
                            <property name="label" value="Medical History"/>
                            <property name="contents">
                                <list>
                                    <bean class="org.openmrs.module.ui.springmvc.web.widget.ObsGroupTableWidget">
                                        <property name="title" value="Allergies / Side Effects"/>
                                        <property name="groupingConceptId" value="1295"/>
                                        <property name="columnConceptIds">
                                            <map>
                                                <entry>
                                                    <key><value>Suspected medication</value></key>
                                                    <value>1296</value>
                                                </entry>
                                                <entry>
                                                    <key><value>Reaction</value></key>
                                                    <value>1297</value>
                                                </entry>
                                                <entry>
                                                    <key><value>Action taken</value></key>
                                                    <value>1643</value>
                                                </entry>
                                            </map>
                                        </property>
                                        <property name="addAnotherFormId" value="5"/>
                                    </bean>
                                    <bean class="org.openmrs.module.ui.springmvc.web.widget.ObsGroupTableWidget">
                                        <property name="title" value="Hospitalizations"/>
                                        <property name="groupingConceptId" value="3801"/>
                                        <property name="columnConceptIds">
                                            <map>
                                                <entry>
                                                    <key><value>Diagnosis</value></key>
                                                    <value>2134</value>
                                                </entry>
                                                <entry>
                                                    <key><value>Date</value></key>
                                                    <value>3290</value>
                                                </entry>
                                                <entry>
                                                    <key><value>Discharge date</value></key>
                                                    <value>3800</value>
                                                </entry>
                                            </map>
                                        </property>
                                        <property name="addAnotherFormId" value="6"/>
                                    </bean>
                                </list>
                            </property>
                        </bean>
                        <bean class="org.openmrs.module.ui.springmvc.web.TabConfiguration">
                            <property name="key" value="labs"/>
                            <property name="label" value="Labs"/>
                            <property name="contents">
                                <list>
                                    <bean class="org.openmrs.module.ui.springmvc.web.widget.FormTableWidget">
                                        <property name="title" value="Lab results"/>
                                        <property name="formId" value="7"/>
                                        <property name="columns">
                                            <list>
                                                <bean class="org.openmrs.module.ui.springmvc.web.widget.SingleConceptColumn">
                                                    <property name="heading"><value><![CDATA[<small>Hb<br/>(g/dl)</small>]]></value></property>
                                                    <property name="conceptId" value="21"/>
                                                </bean>
                                                <bean class="org.openmrs.module.ui.springmvc.web.widget.SingleConceptColumn">
                                                    <property name="heading"><value><![CDATA[<small>Hct<br/>(%)</small>]]></value></property>
                                                    <property name="conceptId" value="1015"/>
                                                </bean>
                                                <bean class="org.openmrs.module.ui.springmvc.web.widget.SingleConceptColumn">
                                                    <property name="heading"><value><![CDATA[<small>GB<br/>(x10<sup>9</sup>/l)</small>]]></value></property>
                                                    <property name="conceptId" value="678"/>
                                                </bean>
                                            </list>
                                        </property>
                                    </bean>
                                </list>
                            </property>
                        </bean>
                        <bean class="org.openmrs.module.ui.springmvc.web.TabConfiguration">
                            <property name="key" value="graphs"/>
                            <property name="label" value="Graphs"/>
                            <property name="contents">
                                <list>
                                    <bean class="org.openmrs.module.ui.springmvc.web.widget.ObsGraphWidget">
                                        <property name="title" value="CD4 History"/>
                                        <property name="conceptId" value="5497"/>
                                        <property name="minY" value="0"/>
                                        <property name="maxY" value="3000"/>
                                    </bean>
                                </list>
                            </property>
                        </bean>
                    </list>
                </property>
            </bean>
        </property>
    </bean>
    
    <!-- This is our main app -->
    <bean id="dataentryApp" class="org.openmrs.module.ui.springmvc.App">
        <property name="parentHomepageUrl" value="/module/rwandamoh/homepage.form"/>
        <property name="name" value="HIV Flowsheet"/>
        <property name="homepageUrl" value="/module/rwandamoh/dataentry/homepage.form"/>
        <property name="iconFilename" value="/moduleResources/ui/springmvc/images/application64.png"/>
    </bean>

    <!-- another app that gives access to the regular OpenMRS admin pages -->
    <bean id="openmrsAdminApp" class="org.openmrs.module.ui.springmvc.App">
        <property name="parentHomepageUrl" value="/module/rwandamoh/homepage.form"/>
        <property name="name" value="Configuration Settings"/>
        <property name="homepageUrl" value="/admin/index.htm"/>
        <property name="iconFilename" value="/moduleResources/ui/springmvc/images/configure64.png"/>
    </bean>

    <!-- Add our two apps to the list of all apps. (Multiple modules can add apps, and they'll all show up) -->
    <bean class="org.openmrs.module.ui.springmvc.AppList" factory-method="getInstance">
        <property name="appsAdditional">
            <list>
                <ref local="dataentryApp"/>
                <ref local="openmrsAdminApp"/>
            </list>
        </property>
    </bean>
           
    <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
    <context:component-scan base-package="@MODULE_PACKAGE@" />
    
</beans>