Adding more sections & Customizable Widgets to the Clinician Dashboard

Continuing the discussion from Final Feature List for Reference Application 2.6: and the 2017-06-06 Design call notes one of the features for the reference application is more customizable widgets for the clinician facing dashboard.

My understanding of the approach is as follows:

  1. The widgets can be added to the dashboard similar to the most Recent Vitals app at https://github.com/openmrs/openmrs-module-coreapps/blob/master/omod/src/main/resources/apps/mostRecentVitals_app.json

  2. Depending on available time, a manage extensions screen https://issues.openmrs.org/browse/RA-923 will assist this process

An initial list of custom widgets which can be added to core apps are below, do provide your feedback and inputs to guide the growth of this list

  1. Concept List Widget - Display a comma delimited list of concepts, share concept IDs or uuids which will be displayed in a list of values. out put will look like

  1. Concept across encounters - provide a comma delimited list of concepts (max 4) which are displayed in a table as below
  2. Graphing of a single numeric concept
  3. Data Integrity Rule violations for a patient provided through the data integrity module

I assume you mean these would be interpreted as most recent obs for each of the concepts individually (e.g. if configured with “weight” and “height” they might get today’s weight, and a height from 2 years ago).

I would also indicate how recent each obs is (e.g. today, yesterday, n days/months/years ago) with a subtle text effect. (And if you hover over it it should show you the exact date.)

(Optionally, support a “maxAge” parameter, e.g. show me PPD result, but not if it’s more than 1 year old.)

This should have a required “max # to show” setting and maybe also an optional “max age”.

I would pull the unit into the header (e.g. “Weight (kg)” rather than putting the weight on every row.

You’ve drawn these in chronological order, but I would usually expect reverse-chronological. (I suggest we default to date descending, but have an option for doing the opposite.)

I would tend to prefer to group this by date rather than by encounter. (We’d need to define what happens if there’s >1 result on a day. Also, it might be useful to have a group-by-month option, but I wouldn’t do that unless a real user asks.)

Ideally this should be right aligned, with the decimal point as an anchor for non-integer values.

@darius Thanks for the feedback. I have taken the first widget - Concept List and put together the following documentation, not sure if OpenMRS has an existing standard which I am happy to follow:

Concept List App Configuration Parameters

Key Required Default Values Description
provider yes coreapps A valid moduleId The provider for the fragment showing the list
fragmented yes section/conceptList a valid fragmentId The id of the fragment that displays the list
concepts yes Comma delimited list of Concept numeric id, uuid, or mapping * Provides the concepts whose most recent obs are returned.
* Minimum of 1 and a maximum of 10 concepts.
* If the concept has no value it is returned with no value
* Text showing how recent the obs is, today, yesterday, n days/months/years ago in smaller italic text whose title is the actual obs date
maxAge no 0 Numeric integer with a suffix for example:
*1d – 1 day
*2w – 2 weeks
*4m – 4 months from the current date
The maximum age of most recent obs for each of the items in the concept list
title yes Concept List String The title of the control
sort no none none
asc
desc
Whether the concepts are sorted by concept name

Image

1 Like

I said the age indicator should be subtle, not highlighted. :slight_smile: In fact I’d even consider doing it more like this (I’m constrained by Talk’s markdown here):

Weight: 50 kg . . . 2 weeks ago

We do not yet have documentation for the available Dashboard Elements. For the next release we should add a catalog of available elements, that is linked to from this section: https://wiki.openmrs.org/display/docs/OpenMRS+Reference+Application+2.x+Implementer+Documentation#OpenMRSReferenceApplication2.xImplementerDocumentation-PatientSummary

The format you’ve laid out looks good.

But I think we should only say required=yes if the consumer is required to specify a value. If there’s a default value, then from the implementer’s perspective the property is optional. (E.g. provider, fragmentId.)

And, just to be very detail-oriented I would say:

  • config parameters that are most interesting to the implementer should go up top, i.e. concepts should be first
  • distinguish between what’s a recommendation vs a limitation/requirement. (E.g. I wouldn’t say “Minimum of 1 and a maximum of 10 concepts”; if the admin wants to put 11 concepts, why would we prevent them from doing that?)
  • Instead of required=yes|no that column should have the value required|optional
  • I would make title be required and not have a default value.
  • personally I don’t see value in the sort parameter

@raff @adamg I have seen this https://issues.openmrs.org/browse/RA-1293 and the resulting PR. Is this a model that we shall use for the new features on this thread? Thoughts and feedback are welcome

Yes, I’d imagine we’ll be doing a similar thing for all the new widgets you mentioned on this thread i.e. using the config section of the _app.json to configure what to display…

@ssmusoke, do you think this is ready for work (assuming we create issues)? Or are you saving it for GSoC?

@raff this is ready for work. I just need to sit down and create draft documentation to kickstart the process. Gsoc will build additional widgets

Great!

Do you mean widgets mentioned in this thread will be built as part of GSoC?

@raff I was hoping that the widgets in this thread would get built before providing a foundation of additional widgets for GSoC.

Perfect! Let’s get them done then! I can setup a sprint tomorrow to work on them. You didn’t create issues yet, did you? I can handle that… Let me know!

@raff you can go ahead and create the issues, I am working on a Wiki page for the documentation that I think will provide some insight into what I am thinking which will be done in the next 2 hours.

@raff Here is a first cut - will add more as they come to mind https://wiki.openmrs.org/display/docs/Patient+Summary+Widget+Documentation

@darius A question on the App Framework:

  1. Can the app templates be inherited, which means that authors do not have to add all fields to all templates

  2. Can application definitions be inherited so that instead of copying all the contents of an appId, I can extend it overwriting the parameters that I need.

1 Like

FYI, I’ve created an epic at https://issues.openmrs.org/browse/RA-1299

Soon we’ll do estimates and create a sprint.

Sprint announced here: Patient Summary Widgets Sprint

1 Like

I don’t think so. Are you sure “app template” is right for this, though? A widget isn’t an app…

We have a disconnect here. I would not expect each widget to be an app or an app template. My current thinking is somewhere in this post.

Can anyone help with the reference registrationapp. i added the attributes: Empresa, grupo sanguĂ­neo, profissĂŁo. it shows in the new patient registration process but does not show in patient dashboard. here is the code below:

{ “id”: “referenceapplication.registrationapp.myRegisterPat”, “instanceOf”: “registrationapp.registerPatient”, “label”: “Cadastrar Paciente”, “description”: “Criar uma ficha para paciente”, “extensions”: [ { “id”: “referenceapplication.registrationapp.registerPatient.homepageLink”, “extensionPointId”: “org.openmrs.referenceapplication.homepageLink”, “type”: “link”, “label”: “referenceapplication.app.registerPatient.label”, “url”: “registrationapp/registerPatient.page?appId=referenceapplication.registrationapp.myRegisterPat”, “icon”: “icon-user”, “order”: 1, “requiredPrivilege”: “App: registrationapp.registerPatient” } ], “config”: { “afterCreatedUrl”: “/coreapps/clinicianfacing/patient.page?patientId={{patientId}}”, “sections”: [ { “id”: “contactInfo”, “label”: “Informação”, “questions”: [

                      {
                        "legend": "Person.address",
                        "fields": [
                            {
                                "type": "personAddress",
                                "label": "registrationapp.patient.address.question",
                                "widget": {
                                    "providerName": "uicommons",
                                    "fragmentId": "field/personAddress"
                                    }
                                }
                            ]
                         },

{ “legend”: “Grupo sanguineo”, “id”: “myPersonAttributeLabel”, “fields”: [ { “type”: “personAttribute”, “label”: “Grupo sanguineo do paciente”, “formFieldName”: “GrupoSanguineo”, “uuid”: “c29cbfbf-3a89-457c-8908-2b8274fa06af”, “widget”: { “providerName”: “uicommons”, “fragmentId”: “field/text” }, “cssClasses”: [“GrupoSanguineo”,“required”] } ] },

                    {
                        "legend": "registrationapp.patient.phone.label",
                        "id": "phoneNumberLabel",
                        "fields": [
                            {
                                "type": "personAttribute",
                                "label": "registrationapp.patient.phone.question",
                                "formFieldName": "phoneNumber",
                                "uuid": "14d4f066-15f5-102d-96e4-000c29c2a5d7",
                                "widget": {
                                    "providerName": "uicommons",
                                    "fragmentId": "field/text"
                                },
                                "cssClasses": ["phone"]
                            }
                        ]
                    }
                ]
            },


            {
                "id": "relationships-info",
                "label": "registrationapp.person.relationship",
                "questions": [
                    {
                        "legend": "registrationapp.person.relationship.label",
                        "header": "registrationapp.person.relationship.question",
                        "fields": [
                            {
                                "type": "personRelationships",
                                "widget": {
                                    "providerName": "registrationapp",
                                    "fragmentId": "field/personRelationship"
                                }
                            }
                        ]
                    }
                ]
            }
        ]
    }
}

Do you mind creating a new post for this?

@ssmusoke I see there is a new graph that overlays height and weight in the patient summary widget wiki. (see below)


I added the code that was provided and modified it to show height and weight concepts:

{

“id”: “custom.obsgraph.weightheight”, “instanceOf”: “coreapps.template.dashboardWidget”, “description”: “coreapps.obsGraph.app.description”, “order”: 10, “config”: { “widget”: “obsgraph”, “icon”: “icon-bar-chart”, “label”: “Obs Graph Height/Weight”, “conceptId”: “5090AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,5089AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA”, “maxResults”: “6”, “maxAge”: “1w” }, “extensions”: [ { “id”: “org.openmrs.module.coreapps.mostRecentVitals.clinicianDashboardFirstColumn”, “appId”: “custom.obsgraph.weightheight”, “extensionPointId”: “patientDashboard.firstColumnFragments”, “extensionParams”: { “provider”: “coreapps”, “fragment”: “dashboardwidgets/dashboardWidget” } } ] } same code here: https://hastebin.com/segesexamu.json

When I saved that code, I get a blank widget with the two concepts but I get the graphs if I only put one or the other concept uuid.

Please advise.

Thank you,

John

@cioan Made nice improvements for dashboard widget graphs and also allowing for logarithm graphs (used for viral load). Appreciation to Cosmin.

1 Like