How to use the App Framework (2.0) ?

This document will demonstrate how to use the OpenMRS app framework version 2.0. The app framework provides a way to define a set of apps and extensions in configuration which can then be accessed using an API. For details on its design, look here.

Apps/Extensions can be defined in the system by using a JSON configuration. This JSON data structure provides the configuration for a particular app/extension. This JSON configuration is placed in a folder with a naming style defined by convention.

Example:

For the app configuration, the configuration loader looks in all "apps" folders directly within the resources directory of the source code which ends in an "app.json" across the entire classpath. 

src

|__main

    |__resources

        |__apps

            |__patient_app.json

Basically the configuration loader looks for all files of type '.*app.json' which may fall under the apps directory. This is checked for all the modules and jars that are deployed. Hence across the entire classpath.

P.S- In case of an extension the location is the same. The only difference is that the file ends in an 'extension.json'. eg., 'xray_extension.json'

So, the first step is to create a file following the above convention.

The following is an example of a sample app file. It contains the definition of 2 apps in one JSON array.

[

    {
        "id": "patientDashboardApp",
        "description": "Patient Dashboard Application",
        "extensionPoints": [
           {"id": "activeVisitActions"},
           { "id": "patientActions" }
        ],
        "contextModel": [ "patientId", "activeVisitId" ]
    },
    {
        "id": "xrayApp",
        "description": "XRay Application",
        "extensionPoints": [
            {"id": "patientLinks" }
        ],
        "contextModel": [ "xrayConceptId", "patientId" ]
    }

]

The above describes two apps, one for a patient dashboard and the other for ordering x-rays. Each app has an id, that uniquely identifies id and a description. It also includes extensionPoints which are used to attach extensions to a particular app. The contextModel is a non-functional field which is used by the app to document the parameters which it exposes. 

The following is the example of a sample extension file. It contains the definition of 2 extensions in one JSON array.

[

    {
        "id": "orderXrayExtension",
        "appId": "patientDashboardApp",
        "extensionPointId": "activeVisitActions",
        "type": "link",
        "label": "Order XRay",
        "url": "/xray/order?patientId=patientId&activeVisitId=activeVisitId",
        "extensionParams": {"iconUrl": "/xray/icon" }
    },
    {
        "id": "gotoPatientExtension",
        "appId": "xrayApp",
        "extensionPointId": "patientLinks",
        "type": "link",
        "label": "Goto Patient",
        "url": "/patientDashboard?patientId=patientId"
    }

] 

The above describes 2 extensions, one for ordering X-rays and the other to go back to a patient page. Each extension defines a unique id. Apart from that it specifies the appId and extensionPointId which are the IDs of the app and the extensionPoint that the extension should be displayed at. There can be various 'type's of extensions which specify how they may be drawn. They also have a url attached which can be change based on current context. 

The following are the list of APIs that can be used to access the app framework

   /**
    * Fetches all apps that have been defined or are available in the system across modules
    *
    * @return - List of all App Descriptors
    **/
    List<AppDescriptor> getAllApps();

    /**
     * Fetches all extensions that have been defined or are available in the system across modules for a particular
     * app at an extension point.
     *
     * @param appId - id of the app
     * @param extensionPointId - id of the extension point.
     * @return - List of all extensions.
     **/
     List<Extension> getAllExtensions(String appId, String extensionPointId);

    /**
     * Fetch only the apps that are enabled (or ignore the apps that are disabled)
     *
     * @return - List of enabled app descriptors
     **/
    List<AppDescriptor> getAllEnabledApps();

    /**
     * Fetch all enabled extensions (or ignore disabled extensions) for a particular app at an extension point.
     *
     * @param appId - id of the app
     * @param extensionPointId - id of the extension point
     * @return - List of all enabled extensions
     **/
    List<Extension> getAllEnabledExtensions(String appId, String extensionPointId);

    /**
     * Enables an app.
     *
     * @param appId - id of the app
     **/
    void enableApp(String appId);

    /**
     * Disables an app.
     *
     * @param appId - id of the app
     **/
    void disableApp(String appId);

    /**
     * Enables an extension.
     *
     * @param extensionId - id of the extension
     **/
    void enableExtension(String extensionId);

    /**
     * Enables an extension.
     *
     * @param extensionId - id of the extension
     **/
    void disableExtension(String extensionId);