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

« Previous Version 2 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.

We also have these slides which sketch a UI. They are similarly ugly.

All of the above, despite its ugliness, should be reviewed to understand the types of functionality that have been envisaged so far.

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).

Here we see the "remove" element editor, which offers a multi-select of the extensions which are currently attached to the slot (and thus available to be removed).

UI Editor

The UI Editor provides the administrator with a visual understanding of what the configuration means.

For the microfrontend configuration, it's simply "edit buttons" in sensible places in the UI which allow the admin to "hop" to the relevant piece of config. For example, turning on the UI Editor, they might see a little Edit button by the logo on the login page. When they click that button, they would be taken to the relevant section of the configuration in the Implementer Tools panel.

The bulk of what the UI Editor does, however, has to do with extensions. It makes it clear to the administrator where all the slots and extensions are.

It should probably also provide features for visually editing the extension configuration—buttons that trigger the corresponding config changes to e.g. remove an extension or reorder it within a slot. This is featured prominently in the presentation linked above.

Challenges

The shape of the configuration is subject to change. New microfrontends may do new and previously unanticipated things with config structure.

The same is true of extensions and extension slots. Who knows what insane things people might try to use them for.


  • No labels