13 UI language
(ns oiiku.ui.impl.docs.ui-language
(:require [scicloj.kindly.v4.kind :as kind]))When working with our UI domain, we try to separate it from the business domain, the technical domain and have a translation layer. We call this the prepare layer, where business domain data is translated in a prepare stage to the language the UI domain understands.
13.1 A concrete example
When sending a message to the server containing an update, we use our API layer called Convey. Convey has a concept of InFlight and SlowRequest, where InFlight means the message has been sent and a response has not yet been received. SlowRequest means that the message has been InFlight for over 1000ms.
If this was fed directly into a widget, we would have tied together the UI layer and the network layer. If we found out later that we want a similar effect on the UI layer as we get for the InFlight status on messages, we would need to mimic the InFlight mechanism, instead of writing something new that works with what we need. To avoid this problem, a new state called Disabled is introduced, where a button can be Disabled (ie, you cannot interact with it) and how it is disabled is not something that the button decides.
Button has a UI language (Disabled), which is separate from what could cause it (InFlight). When the message becomes SlowRequest, we might want to show that in the button, in which case the UI State becomes Loading (shows a spinner).
To further complicate things we can have a composite of widgets that logically is tied together, e.g. a form. We want a UI language that can describe what happens with a form when a message is InFlight or is SlowRequest, which might or might not be the same as a Button inside.
13.2 UI Language Dictionary
Dictionary of UI Language words and what they mean.
13.2.1 Disabled
The widget is set into a disabled state, in which it can no longer receive input and it’s visually shown that the widget is disabled.
13.2.2 Read-only
The widget is set in a read-only state, in which it can no longer receive input, but does not show so visually.
13.2.3 Loading
The widget is set into a Loading state, in which it visually (i.e. a spinner) shows that it’s waiting for input from the app itself, e.g. a message response.
13.2.4 Closable
The widget is set to be Closable or not Closable. If it’s set to not be Closable you cannot close the widget. For modals this would mean that you cannot close the modal via either Escape or via some button click. For a menu it would mean you cannot move out of the menu.
13.3 Flowchart simple modal window
In this flowchart there is a modal window containing two buttons: Cancel and Save. When pressing Save, a network message is sent to the server and the Save button is disabled. The modal can no longer be dimissed with an Escape press, nor will the X button on the top right work.
(kind/mermaid
"flowchart TD
Store --> State
State --> RenderModal{Render modal?}
RenderModal -->|Yes| ModalPrepare{Modal prepare fn}
RenderModal -->|No| Nothing
ModalPrepare -->|InFlight| RenderDisabled(Set disabled)
ModalPrepare -->|SlowRequest| RenderSlow(Set loading)
ModalPrepare -->|Locked?| RenderLocked(Set locked)
ModalPrepare -->|Pass| RenderNormal(Pass)
RenderDisabled --> CancelButton(Cancel button)
RenderLocked --> CancelButton
RenderNormal --> CancelButton
CancelButton --> CancelActions(Actions for Cancel button)
CancelActions -->|Click - remove modal| Store
RenderLocked --> Modal
RenderNormal --> Modal
Modal -->|Escape pressed| Escape{Locked?}
Escape -->|Yes| Modal
Escape -->|No - remove modal| Store
RenderDisabled --> SaveButton(Save button)
RenderSlow --> SaveButton
RenderLocked --> SaveButton
RenderNormal --> SaveButton
SaveButton --> SaveActions(Actions for Save button)
SaveActions -->|Network request| ConveyMessage
ConveyMesssage -->|Set InFlight| Store
ConveyMessage -->|Set timeout|Timeout
Timeout -->|Triggered - set SlowRequest| Store
SaveActions -->|Set locked| Store")13.4 Sequence diagram
(kind/mermaid
"sequenceDiagram
Modal ->> Save: Renders Save button
Modal ->> Cancel: Renders Cancel button
Save ->> EffectConvey: A click causes an effect to dispatch to Convey
Save ->> ActionLockUI: A click locks the UI for the modal
ActionLockUI ->> UIState: UI state is set to locked for the modal
UIState ->> Cancel: Cancel button is locked and cannot be interacted with
EffectConvey ->> Convey: The effect tells Convey to send a message to the server
Convey ->> UIState: UI State is set to inflight for the message
UIState ->> Prepare: Save is set to disabled
EffectConvey ->> UIState: An update is happening
Prepare ->> Save: Save is rendered as disabled
Convey ->> Timeout: A timeout is set that can fire a slow request
Timeout ->> UIState: UI State is set to slow-request for the message
UIState ->> Prepare: Save is set to loading
Prepare ->> Save: Save is rendered with a spinner
Convey ->> UIState: A response is received and UI is unlocked and message is no longer in flight
UIState ->> Modal: Re-render everything from the top")source: bases/admin-web/src/oiiku/ui/impl/docs/ui_language.clj