Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

Goal

To provide an interface that allows non-technical system administrators to configure the frontend application.

Secondarily, to provide other interfaces (other tabs/panels, for example) which provide additional insights, controls, and diagnostic information to the system administrator. For example, diagnostic information about missing backend modules.

Starting Point

We have an application, the Implementer Tools, which provides a janky interface for managing configuration.

It is basically functional, but unambiguously ugly.

Functional Specification

There are essentially the following main parts: microfrontend configuration, extension configuration, and the UI editor.

The application is configured with one or more config files. These files override the default config values. All config values have defaults. The Implementer Tools provides an interface for editing the configuration of the application. When an administrator "edits the configuration," everything they do is local only to them, saved in the "temporary config," which is essentially a config overrides file that lives in LocalStorage. In order to deploy their changes to the server, they can download that temporary config and add it as a config file to their application. Brandon is working on a feature that would allow saving the new config values to the server by clicking a button.

A config file is a JSON file with microfrontend names for top-level keys. e.g.

{
  "@openmrs/esm-login-app": {
    "chooseLocation": {
      "enabled": false
    }
  },
  "@openmrs/esm-home-app": {
    "buttons": {
      "enabled": true
    }
  }
}

Microfrontend Configuration

Microfrontend Configuration is used to tell microfrontends how to behave; for example, the login page can be configured to show a different logo than the default.

There are the following types of possible config values:

  • Boolean
  • Number
  • String
    • UUID
      • ConceptUuid
  • Array (e.g. `["foo", "bar"]`)
  • Freeform Object (e.g. `{ foo: "bar", baz: 3 }`)

To clarify a little, the entire config tree is an "object" in the sense that it is a thing with keys and values, potentially nested. However, its keys are completely prescribed. Hence the type "Freeform Object", which is a value in which the keys are not prescribed. These are rare and you don't need to worry about them too much.

Arrays and Freeform Objects can contain any of the above as values, including other Arrays and Freeform Objects. The most common structures involving these things are 1. a simple Array of Strings and 2. an Array of predefined Objects.

An Array of Objects carries some specification of its member objects (c.f. an Array of Freeform Objects). So it might want objects with keys "foo" and "bar," where "foo" is a string and "bar" is an optional boolean. So

[{ foo: "hey" }, { foo: "you", bar: false }, { foo: "get" }]

would be a valid value but

[{ foo: "hey" }, { bar: false }, { foo: "get" }]

would not, because the required element "foo" is absent. Nor would

[{ foo: "hey" }, { buzz: "bad" }, { foo: "get" }]

wherein one object has an element that is not part of the member object spec.

Editing

  • Editing basic config values. These are booleans, numbers, or strings.
  • Editing arrays. Should be able to add, remove, and reorder elements. For arrays of objects, adding an element to the array should add an object with the correct shape.
  • Editing freeform objects? Literal JSON editing might be the best we can do, here, since values can be of any type.

Feedback

  • Each config element has a description, a default value, a source for the current value, and a set of validators. These should be displayed.
  • Some config elements have corresponding "edit buttons" in the UI editor (which may or may not be present on the page which the administrator is on. Maybe there's a good way to highlight the relationship, when the admin happens to be on the right page?
  • When the admin inputs a value that is invalid (either because it is of the wrong type or because it fails a validator), they should know about it.
  • It should probably be visually apparent which config values are defaults, which have been set in a config file, and which have been set in the UI / temporary config.
  • If there is a config file that is providing configuration for a microfrontend that doesn't exist, the admin should be made aware of this, as it might indicate an error (but does not necessarily).

Extension Configuration

Extension Configuration is used to customize the relationships between extensions and slots. Every extension is attached to some slots in code, and has some order-priority (think z-index) within those slots. Using configuration, this behavior can be changed: extensions can be removed from slots they are attached to in code, added to slots that they are not attached to in code, and reordered within slots. Each extension is also itself configurable, like a microfrontend. Think of a line graph which can plot observations for any numeric concept. If it is provided as an extension, it can be attached in multiple places, configured to plot a different concept in each place.

Whereas the microfrontend configuration is completely variable, the extension configuration follows a very predictable structure. Each slot can be configured as

  • (containing module name)
    • slots
      • (slot name)
        • add: (array of extension IDs)
        • remove: (array of extension IDs)
        • order: (array of extension IDs)
        • configure
          • (extension ID): (whatever config object the extension wants)

Other than the "configure" element, it's quite straightforward.

Any extension can technically be added to any slot, but few extension-slot pairings will actually work correctly. It's unclear how we should address this, but perhaps the simplest way would be to assign slots and extensions "types" so that they can be associated with each other. Each "type" would have some expected shape of state object. Alternatively, extensions could make their requirements known to the extension system (the extension system already has access to the state provided by slots).

  • No labels