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>