The aim of this document is to:
-
Explain what OperatorFabric is about and define the concepts it relies on
-
Give a basic tour of its features from a user perspective
-
Describe the technical implementation that makes it possible
1. Introduction
To perform their duties, an operator has to interact with multiple applications (perform actions, watch for alerts, etc.), which can prove difficult if there are too many of them.
The idea is to aggregate all the notifications from all these applications into a single screen, and to allow the operator to act on them if needed.
These notifications are materialized by cards sorted in a feed according to their period of relevance and their severity. When a card is selected in the feed, the right-hand pane displays the details of the card: information about the state of the parent process instance in the third-party application that published it, available actions, etc.
In addition, the cards will also translate as events displayed on a timeline (its design is still under discussion) at the top of the screen. This view will be complimentary to the card feed in that it will allow the operator to see at a glance the status of processes for a given period, when the feed is more like a "To Do" list.
Part of the value of OperatorFabric is that it makes the integration very simple on the part of the third-party applications. To start publishing cards to users in an OperatorFabric instance, all they have to do is:
-
Register as a publisher through the "Thirds" service and provide a "bundle" containing handlebars templates defining how cards should be rendered, i18n info etc.
-
Publish cards as json containing card data through the card publication API
OperatorFabric will then:
-
Dispatch the cards to the appropriate users (by computing the actual users who should receive the card from the recipients rules defined in the card)
-
Take care of the rendering of the cards, displaying details, actions, inputs etc.
-
Display relevant information from the cards in the timeline
Another aim of OperatorFabric is to make cooperation easier by letting operators forward or send cards to other operators, for example:
-
If they need an input from another operator
-
If they can’t handle a given card for lack of time or because the necessary action is out of their scope
This will replace phone calls or emails, making cooperation more efficient and traceable.
For instance, operators might be interested in knowing why a given decision was made in the past: the cards detailing the decision process steps will be accessible through the Archives screen, showing how the operators reached this agreement.
2. A quick walk through the user interface
Work in progress
3. Technical overview
4. Thirds service
As stated above, third-party applications (or "thirds" for short) interact with OperatorFabric by sending cards. The Thirds service allows them to tell OperatorFabric
-
how these cards should be rendered
-
what actions should be made available to the operators regarding a given card
-
if several languages are supported, how cards should be translated
In addition, it lets third-party applications define additional menu entries for the navbar (for example linking back to the third-party application) that can be integrated either as iframe or external links.
4.1. Declaring a Third Party Service
This sections explains Third Party Service Configuration
The third party service configuration is declared using a bundle which is described below. Once this bundle fully created, it must be uploaded to the server which will apply this configuration into current for further web UI calls.
The way configuration is done is explained throughout examples before a more technical review of the configuration details. The following instructions describe tests to perform on OperatorFabric to understand how customization is working in it. The card data used here are send automatically using a script as describe here Cards sending script.
4.1.1. Requirements
Those examples are played in an environment where an OperatorFabric instance (all micro-services) is running along a MongoDB Database and a RabbitMQ instances.
4.1.2. Bundle
Third bundles customize the way third card details are displayed. Those tar.gz
archives contain a descriptor file
named config.json
, eventually some css files
, i18n files
and handlebars templates
to do so.
For didactic purposes, in this section, the third name is BUNDLE_TEST
(to match the parameters used by the script).
This bundle is localized for en
and fr
.
As detailed in the Third core service README
the bundle contains at least a metadata file called config.json
,
a css
folder, a media
folder (not created in this example), an i18n
folder and a template
folder.
All elements except the config.json file
are optional.
The files of this example are organized as below:
bundle ├── config.json ├── css │ └── bundleTest.css ├── i18n │ ├── en.json │ └── fr.json └── template ├── en │ ├── template1.handlebars │ └── template2.handlebars └── fr ├── template1.handlebars └── template2.handlebars
To summarize, there are 5 directories and 8 files.
The config.json file
It’s a description file in json
format. It lists the content of the bundle.
example
{ "name": "BUNDLE_TEST", "version": "1", "csses": [ "bundleTest" ], "i18nLabelKey": "third-name-in-menu-bar", "menuEntries": [ { "id": "uid test 0", "url": "https://opfab.github.io/whatisopfab/", "label": "first-menu-entry" }, { "id": "uid test 0", "url": "https://www.lfenergy.org/", "label": "b-menu-entry" }, { "id": "uid test 1", "url": "https://github.com/opfab/opfab.github.io", "label": "the-other-menu-entry" } ], "processes" : { "simpleProcess" : { "start" : { "details" : [ { "title" : { "key" : "start.first.title" }, "titleStyle" : "startTitle text-danger", "templateName" : "template1" } ], "actions" : { "finish" : { "type" : "URL", "url": "http://somewher.org/simpleProcess/finish", "lockAction" : true, "called" : false, "updateStateBeforeAction" : false, "hidden" : true, "buttonStyle" : "buttonClass", "label" : { "key" : "my.card.my.action.label" }, } } }, "end" : { "details" : [ { "title" : { "key" : "end.first.title" }, "titleStyle" : "startTitle text-info", "templateName" : "template2", "styles" : [ "bundleTest.css" ] } ] } } } }
-
name: third name;
-
version: enable the correct display, even the old ones as all versions are stored by the server. Your card has a version field that will be matched to third configuration for correct rendering ;
-
processes : list the available processes and their possible states; actions and templates are associated to states
-
css file template list as
csses
; -
third name in the main bar menu as
i18nLabelKey
: optional, used if the third service add one or several entry in the OperatorFabric main menu bar,cf menu entries section for details; -
extra menu entries as
menuEntries
: optional, see below for the declaration format of objects of this array, cf menu entries section for details.
The mandatory declarations are name
and version
attributes.
i18n
There are two ways of i18n for third service. The first one is done using l10n files which are located in the i18n
folder, the second one throughout l10n name folder nested in the template
folder or in the media
folder.
The i18n
folder contains one json file per l10n.
These localisation is used for integration of the third service into OperatorFabric, i.e. the label displayed for the third service, the label displayed for each tab of the details of the third card, the label of the actions in cards if any or the additional third entries in OperatorFabric(more on that at the chapter ????).
Template and Media folders
The template
and the media
folder must contain localized folder for the i18n of the card details. This is why in our example, as the bundle is localized for en
and fr
language, the template
folder contains a en
and a fr
folder.
If there is no i18n file or key is missing, the i18n key is displayed in OperatorFabric.
The choice of i18n keys is left to the Third service maintainer. The keys are referenced in the following places:
-
config.json
file:-
i18nLabelKey
: key used for the label for the third service displayed in the main menu bar of OperatorFabric; -
label
ofmenu entry declaration
: key used to l10n themenu entries
declared by the Third party in the bundle;
-
-
card data
: values ofcard title
andcard summary
refer toi18n keys
as well askey attribute
in thecard detail
section of the card data.
example
So in this example the third service is named Bundle Test
with BUNDLE_TEST
technical name. The bundle provide an english and a french l10n.
The example bundle defined an new menu entry given access to 3 entries. The title and the summary have to be l10n, so needs to be the 2 tabs titles.
The name of the third service as displayed in the main menu bar of OperatorFabric. It will have the key "third-name-in-menu-bar"
. The english l10n will be Bundle Test
and the french one will be Bundle de test
.
A name for the three entries in the third entry menu. Their keys will be in order "first-menu-entry"
, "b-menu-entry"
and "the-other-menu-entry"
for an english l10n as Entry One
, Entry Two
and Entry Three
and in french as Entrée une
, Entrée deux
and Entrée trois
.
The title for the card and its summary. As the card used here are generated by the script of the cards-publication
project we have to used the key declared there. So they are respectively process.title
and process.summary
with the following l10ns for english: Card Title
and Card short description
, and for french l10ns: Titre de la carte
and Courte description de la carte
.
A title for each (two of them) tab of the detail cards. As for card title and card summary, those keys are already defined by the test script. There are "process.detail.tab.first"
and "process.detail.tab.second"
. For english l10n, the values are First Detail List
and Second Detail List
and for the french l10n, the values are Première liste de détails
and Seconde liste de détails
.
Here is the content of en.json
{ "third-name-in-menu-bar":"Bundle Test", "first-menu-entry":"Entry One", "b-menu-entry":"Entry Two", "the-other-menu-entry":"Entry Three", "process":{ "title":"Card Title", "summary":"Card short description", "detail":{ "tab":{ "first":"First Detail List", "second":"Second Detail List" } } } }
Here the content of fr.json
{ "third-name-in-menu-bar":"Bundle de test", "first-menu-entry":"Entrée une", "b-menu-entry":"Entrée deux", "the-other-menu-entry":"Entrée trois", "process":{ "title":"Titre de la carte", "summary":"Courte description de la carte", "detail":{ "tab":{ "first":"Première liste de détails", "second":"Deuxième liste de détails" } } } }
Once the bundle is correctly uploaded, the way to verify if the i18n have been correctly uploaded is to use the GET method of third api for i18n file.
The service is described here and can be used directly in the browser using the Swagger UI - Third get i18n. The locale
language, the version
of the bundle and the technical name
of the third party are needed to get json in the response.
To verify if the french l10n data of the version 1 of the BUNDLE_TEST third party we could use the following command line curl -X GET "http://localhost:2100/thirds/BUNDLE_TEST/i18n?locale=fr&version=1" -H "accept: application/json"
.
The service response with a 200 status and with the json corresponding to the defined fr.json file show below.
{ "third-name-in-menu-bar":"Bundle de test", "first-menu-entry":"Entrée une", "b-menu-entry":"Entrée deux", "the-other-menu-entry":"Entrée trois", "tests":{ "title":"Titre de la carte", "summary":"Courte description de la carte", "detail":{ "tab":{ "first":"Première liste de détails", "second":"Deuxième liste de détails" } } } }
Menu Entries
Those elements are declared in the config.json
file of the bundle.
If there are several items to declare for a third service, a title for the third menu section need to be declared within the i18nLabelKey
attribute, otherwise the first and only menu entry
item is used to create an entry in the menu nav bar of OperatorFabric.
This kind of objects contains the following attributes :
-
id
: identifier of the entry menu in the UI; -
url
: url opening a new page in a tab in the browser; -
label
: it’s an i18n key used to l10n the entry in the UI.
In the following examples, only the part relative to menu entries in the config.json
file is detailed, the other parts are omitted and represented with a '…'.
Single menu entry
{ … "menuEntries":[{ "id": "identifer-single-menu-entry", "url": "https://opfab.github.io", "label": "single-menu-entry-i18n-key" }], }
Several menu entries
Here a sample with 3 menu entries.
{ … "i18nLabelKey":"third-name-in-menu-navbar", "menuEntries": [{ "id": "firstEntryIdentifier", "url": "https://opfab.github.io/whatisopfab/", "label": "first-menu-entry" }, { "id": "secondEntryIdentifier", "url": "https://www.lfenergy.org/", "label": "second-menu-entry" } , { "id": "thirdEntryIdentifier", "url": "https://opfab.github.io", "label": "third-menu-entry" }] }
Processes and States
Processes and their states allows to match a Third Party service process specific state to a list of templates for card details and actions allowing specific card rendering for each state of the business process.
The purpose of this section is to display elements of third card data in a custom format.
Regarding the card detail customization, all the examples in this section will be based on the cards generated by the script existing in the Cards-Publication
project. For the examples given here, this script is run with arguments detailed in the following command line:
$OPERATOR_FABRIC_HOME/services/core/cards-publication/src/main/bin/push_card_loop.sh --publisher BUNDLE_TEST --process tests
where:
-
$OPERATOR_FABRIC_HOME
is the root folder of OperatorFabric where tests are performed; -
BUNDLE_TEST
is the name of the Third party; -
tests
is the name of the process referred by published cards.
The process entry in the configuration file is a dictionary of processes, each key maps to a process definition. A process definition is itself a dictionary of states, each key maps to a state definition. A state is defined by:
-
a list of details: details are a combination of an internationalized title (title), css class styling element (titleStyle) and a template reference
-
a dictionary of actions: actions are described in the bellow Actions section.
{ "type" : "URL", "url": "http://somewher.org/simpleProcess/finish", "lockAction" : true, "called" : false, "updateStateBeforeAction" : false, "hidden" : true, "buttonStyle" : "buttonClass", "label" : { "key" : "my.card.my.action.label" } }
An action aggregates both the mean to trigger action on the third party and data for an action button rendering:
-
type - mandatory: for now only URL type is supported:
-
URL: this action triggers a call to an external REST end point
-
-
url - mandatory: a template url for URL type action. this url may be injected with data before actions call, data are specified using curly brackets. Available parameters:
-
processInstance: the name/id of the process instance
-
process: the name of the process
-
state: the state name of the process
-
jwt: the jwt token of the user
-
data.[path]: a path to object in card data structure
-
-
hidden: if true, action won’t be visible on the card but will be available to templates
-
buttonStyle: css style classes to apply to the action button
-
label: an i18n key and parameters used to display a tooltip over the button
-
lockAction: not yet implemented
-
updateStateBeforeAction: not yet implemented
-
called: not yet implemented
For in depth information on the behavior needed for the third party rest endpoints refer to the Actions service reference.
For demonstration purposes, there will be two simple templates. For more advance feature go to the section detailing the handlebars templates in general and helpers available in OperatorFabric.
As the card used in this example are created above, the bundle template folder needs to contain 2 templates: template1.handlebars
and template2.handlebars
.
examples of template (i18n versions)
/template/en/template1.handlers
<h2>Template Number One</h2> <div class="bundle-test">'{{card.data.level1.level1Prop}}'</div>
/template/fr/template1.handlers
<h2>Patron numéro Un</h2> <div class="bundle-test">'{{card.data.level1.level1Prop}}'</div>
Those templates display a l10n title and an line containing the value of the scope property card.level1.level1Prop
which is This is a root property
.
/template/en/template2.handelbars
<h2>Second Template</h2> <ul class="bundle-test-list"> {{#each card.data.level1.level1Array}} <li class="bunle-test-list-item">{{this.level1ArrayProp}}</li> {{/each}} </ul>
/template/fr/template2.handelbars
<h2>Second patron</h2> <ul class="bundle-test-list"> {{#each card.data.level1.level1Array}} <li class="bunle-test-list-item">{{this.level1ArrayProp}}</li> {{/each}} </ul>
Those templates display also a l10n title and a list of numeric values from 1 to 3.
This folder contains regular css files.
The file name must be declared in the config.json
file in order to be used in the templates and applied to them.
As above, all parts of files irrelevant for our example are symbolised by a …
character.
Declaration of css files in config.json
file
{ … "csses":["bundleTest"] … }
CSS Class used in ./template/en/template1.handlebars
… <div class="bundle-test">'{{card.data.level1.level1Prop}}'</div> …
As seen above, the value of {{card.data.level1.level1Prop}}
of a test card is This is a level1 property
Style declaration in ./css/bundleTest.css
.h2{ color:#fd9312; font-weight: bold; }
Expected result
Upload
For this, the bundle is submitted to the OperatorFabric server using a POST http method as describe in the Third Service API documentation.
It’s possible for test purposes to use the swagger documentation of the OperatorFabric using the following url https//:$OPERATOR_FABRIC_ROOT_URL:2100/swagger-ui.html#/thirds/uploadBundle
where $OPERATOR_FABRIC_ROOT_URL
is the url of the running OperatorFabric tested.
Example :
cd $BUNDLE_FOLDER curl -X POST "http://localhost:2100/thirds" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "file=@bundle-test.tar.gz;type=application/gzip"
Where:
-
$BUNDLE_FOLDER
is the folder containing the bundle archive to be uploaded. -
bundle-test.tar.gz
is the name of the uploaded bundle.
These command line should return a 200 http status
response with the details of the content of the bundle in the response body such as :
{ "mediasData": null, "menuEntriesData": [ { "id": "uid test 0", "url": "https://opfab.github.io/whatisopfab/", "label": "first-menu-entry" }, { "id": "uid test 0", "url": "https://www.lfenergy.org/", "label": "b-menu-entry" }, { "id": "uid test 1", "url": "https://github.com/opfab/opfab.github.io", "label": "the-other-menu-entry" } ], "name": "BUNDLE_TEST", "version": "1", "csses": [ "bundleTest" ], "i18nLabelKey": "third-name-in-menu-bar", "medias": null, "menuEntries": [ { "id": "uid test 0", "url": "https://opfab.github.io/whatisopfab/", "label": "first-menu-entry" }, { "id": "uid test 0", "url": "https://www.lfenergy.org/", "label": "b-menu-entry" }, { "id": "uid test 1", "url": "https://github.com/opfab/opfab.github.io", "label": "the-other-menu-entry" } ], "processes" : { "simpleProcess" : { "start" : { "details" : [ { "title" : { "key" : "start.first.title" }, "titleStyle" : "startTitle text-danger", "templateName" : "template1" } ], "actions" : { "finish" : { "type" : "URL", "url": "http://somewher.org/simpleProcess/finish", "lockAction" : true, "called" : false, "updateStateBeforeAction" : false, "hidden" : true, "buttonStyle" : "buttonClass", "label" : { "key" : "my.card.my.action.label" }, } } }, "end" : { "details" : [ { "title" : { "key" : "end.first.title" }, "titleStyle" : "startTitle text-info", "templateName" : "template2", "styles" : [ "bundleTest.css" ] } ] } } } }
Otherwise please refer to the trouble shooting section to resolve the problem.
4.2. Bundle Technical overview
See the model section of the swagger generated documentation for data layout
4.2.1. Resource serving
CSS
CSS 3 style sheet are supported, they allow custom styling of card template
detail all css selector must be prefixed by the .detail.template
parent
selector
Internationalization
Internationalization (i18n) files are json file (JavaScript Object Notation). One file must be defined by module supported language. See the model section of the swagger generated documentation for data layout.
Sample json i18n file
{ "emergency": { "message": "Emergency situation happened on {{date}}. Cause : {{cause}}." "module": { "name": "Emergency Module", "description": "The emergency module managed ermergencies" } } }
i18n messages may include parameters, these parameters are framed with double curly braces.
The bundled json files name must conform to the following pattern : [lang].json
ex:
fr.json en.json de.json
Media (notification sounds)
Supported media files type : * ogg * wav * mp3
Due to web nature of OperatorFabric, we encourage business modules provider to favor the lightest file formats (ogg,mp3, …)
Templates
Templates are Handlebars template files. Templates are fuelled with a scope structure composed of
-
a card property (See card data model for more information)
-
a userContext :
-
login: user login
-
token: user jwt token
-
firstName: user first name
-
lastName: user last name
-
In addition to Handlebars basic syntax and helpers, OperatorFabric defines the following helpers :
numberFormat
formats a number parameter using developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Nu mberFormat[Intl.NumberFormat]. The locale used is the current user selected one, and options are passed as hash parameters (see Handlebars doc Literals section).
{{numberFormat card.data.price style="currency" currency="EUR"}}
dateFormat
formats the submitted parameters (millisecond since epoch) using mement.format. The locale used is the current user selected one, the format is "format" hash parameter (see Handlebars doc Literals section).
{{dateFormat card.data.birthday format="MMMM Do YYYY, h:mm:ss a"}}
slice
extracts a sub array from ann array
example:
<!-- {"array": ["foo","bar","baz"]} --> <ul> {{#each (slice array 0 2)}} <li>{{this}}</li> {{/each}} </ul>
outputs:
<ul> <li>foo</li> <li>bar</li> </ul>
and
<!-- {"array": ["foo","bar","baz"]} --> <ul> {{#each (slice array 1)}} <li>{{this}}</li> {{/each}} </ul>
outputs:
<ul> <li>bar</li> <li>baz</li> </ul>
now
outputs the current date in millisecond from epoch. The date is computed from application internal time service and thus may be different from the date that one can compute from javascript api which relies on the browsers' system time.
NB: Due to Handlebars limitation you must provide at least one argument to helpers otherwise, Handlebars will confuse a helper and a variable. In the bellow example, we simply pass an empty string.
example:
<div>{{now ""}}</div> <br> <div>{{dateFormat (now "") format="MMMM Do YYYY, h:mm:ss a"}}</div>
outputs
<div>1551454795179</div> <br> <div>mars 1er 2019, 4:39:55 pm</div>
for a local set to FR_fr
preserveSpace
preserves space in parameter string to avoid html standard space trimming.
{{preserveSpace card.data.businessId}}
bool
returns a boolean result value on an arithmetical operation (including object equality) or boolean operation.
Arguments: - v1: left value operand - op: operator (string value) - v2: right value operand
arithmetical operators:
-
==
-
===
-
!=
-
!==
-
<
-
⇐
-
>
-
>=
boolean operators:
-
&&
-
||
examples:
{{#if (bool v1 '<' v2)}} v1 is strictly lower than v2 {{else}} V2 is lower or equal to v1 {{/if}}
math
returns the result of a mathematical operation.
arguments:
-
v1: left value operand
-
op: operator (string value)
-
v2: right value operand
arithmetical operators:
-
+
-
-
-
*
-
/
-
%
example:
{{math 1 '+' 2}}
split
splits a string into an array based on a split string.
example:
<ul> {{#each (split 'my.example.string' '.')}} <li>{{this}}</li> {{/each}} </ul>
outputs
<ul> <li>my</li> <li>example</li> <li>string</li> </ul>
action
outputs a card action button whose card action id is the concatenation of an arbitrary number of helper arguments
{{{action "PREREQUISITE_" id}}}
svg
outputs a svg tag with lazy loading, and missing image replacement message. The image url is the concatenation of an arbitrary number of helper arguments
{{{svg baseUri scheduledOpId "/" substation "/before/" computationPhaseOrdinal}}}
i18n
outputs a i18n result from a key and some parameters. There are two ways of configuration :
-
Pass an object as sole argument. The object must contain a key field (string) and an optional parameter field (map of parameterKey ⇒ value)
{{i18n card.data.i18nTitle}}
-
Pass a string key as sole argument and use hash parameters (see Handlebars doc Literals section) for i18n string parameters.
<!-- emergency.title=Emergency situation happened on {{date}}. Cause : {{cause}}. --> {{i18n "emergency.title" date="2018-06-14" cause="Broken Cofee Machine"}}
outputs
Emergency situation happened on 2018-06-14. Cause : Broken Cofee Machine
sort
sorts an array or some object’s properties (first argument) using an optional field name (second argument) to sort the collection on this fields natural order.
If there is no field argument provided :
-
for an array, the original order of the array is kept ;
-
for an object, the structure is sorted by the object field name.
<!-- users : {"john": { "firstName": "John", "lastName": "Cleese"}, "graham": { "firstName": "Graham", "lastName": "Chapman"}, "terry": { "firstName": "Terry", "lastName": "Gilliam"}, "eric": { "firstName": "Eric", "lastName": "Idle"}, "terry": { "firstName": "Terry", "lastName": "Jones"}, "michael": { "firstName": "Michael", "lastName": "Palin"}, --> <ul> {{#each (sort users)}} <li>{{this.firstName}} {{this.lastName}}</li> {{/each}} </ul>
outputs :
<ul> <li>Eric Idle</li> <li>Graham Chapman</li> <li>John Cleese</li> <li>Michael Pallin</li> <li>Terry Gilliam</li> <li>Terry Jones</li> </ul>
and
<ul> {{#each (sort users "lastName")}} <li>{{this.firstName}} {{this.lastName</li> {{/each}} </ul>
outputs :
<ul> <li>Graham Chapman</li> <li>John Cleese</li> <li>Terry Gilliam</li> <li>Eric Idle</li> <li>Terry Jones</li> <li>Michael Pallin</li> </ul>
5. OperatorFabric Users Service
The User service manages users and groups.
- Users
-
represent account information for person destined to receive cards in the OperatorFabric instance.
- Groups
-
-
represent set of users destined to receive collectively some cards.
-
can be used in a way to handle rights on card reception in OperatorFabric.
-
The user define here is an internal representation of the individual card recipient in OperatorFabric the authentication is leave to specific OAuth2 external service.
|
In the following commands the $token is an authentication token currently valid for the OAuth2 service used by the current OperatorFabric system.
|
5.1. Users and Groups
User service manager users and groups.
5.1.1. Users
Users are the individuals and mainly physical person who can log in OperatorFabric.
The access to this service has to be authorized, in the OAuth2
service used by the current OperatorFabric
instance, at least to access User information and to manage Users. The membership of groups is stored in the user information.
Automation creation users
In case of an user does exist in a provided authentication service but he does not exist in the OperatorFabric
instance, when he is authenticated and connected
for the first time in the OperatorFabric
instance, the user is automatically created in the system with no attached groups.
The administration of the groups is dealt by the administrator manually. More details about automation creation user
[here]
5.1.2. Groups
The notion of group is loose and can be used to simulate role in OperatorFabric
. Groups are used to send cards to several users without name them specifically. The information about membership to a group is stored in the user information. The rules used to send cards are describe in the Card Publication Service.
Alternative way to manage groups
The standard way to handle groups in OperatorFabric
instance is dealt on the user information.
There is an alternative way to manage groups through the authentication token, the groups are defined by the administrator of the authentication service.
[here] for more details to use this feature.
6. Cards Publication Service
The Cards Publication Service exposes a REST API through which third-party applications, or "publishers" can post cards to OperatorFabric. It then handles those cards:
-
Time-stamping them with a "publishDate"
-
Sending them to the message broker (RabbitMQ) to be delivered in real time to the appropriate operators
-
Persisting them to the database (MongoDB) for later consultation
6.1. Card Structure
Cards are modelized as Json
objects. The technical design of card is describe in the swagger api description of Card Publication Service. A card correspond to the state of a Process in OperatorFabric.
6.1.1. Technical Information of the card
Those attributes are used by OperatorFabric to manage how cards are stored, to whom and when they’re sent.
Mandatory information
Below, the json
technical key is in the '()' following the title.
Publisher (publisher
)
Quite obviously it’s the Third party which publish the card. This information is used to look up for Presentation resources of the card.
Publisher Version (publisherVersion
)
Refers the version
of publisher third
to use to render this card (i18n, title, summary, media and details).
As through time, the presentation of a publisher card data changes, this changes are managed through publisherVersion
in OperatorFabric. Each version is keep in the system in order to be able to display correctly old cards.
Process Identifier (processId
)
It’s the way to identify the process to which the card is associated. A card represent a state of a process.
Start Date (startDate
)
This attribute is a part of the card life management system. It’s indicate OperatorFabric the moment since the card can be displayed to the operators or main recipients, see Displaying rules.
Severity (severity
)
The severity is a core principe of the OperatorFabric Card system. There are 4 severities available(Technical definition of OperatorFabric Card Severity). A color is associated in the GUI to each severity. Here the details about severity and their meaning for OperatorFabric:
-
ALARM: represents a critical state of the associated process, need an action from the operator. In the Gui, the card is red;
-
ACTION: the associated process need an action form operators in order to evolve correctly. In the Gui, an action is orange;
-
COMPLIANT: the process related to the card is in a compliant status. In the UI, an action is green.;
-
INFORMATION: give information to the operator. In the GUI, a information is blue.
Title (title
)
This attribute is display as header of a card in the feed of the GUI. It’s the main User destined Information of a card. The value refer to an i18n
value used to localized this information.
Summary (summary
)
This attribute is display as a description of a card in the feed of the GUI, when the card is selected by the operator. It’s completing the information of the card title. The value refer to an i18n
value used to localized this information.
Recipient (recipient
)
Declares to whom the card is send. For more details about way recipient works see Displaying rules. Without recipient declaration a card is useless in OperatorFabric
system.
Store information
Tags (tag
)
Tags are intended to enable filter of cards in the feed of the GUI.
uid (uid
)
Unique identifier of the card in the OperatorFabric system. This attribute can be send with card, but normally it’s manage by OperatorFabric
system.
id (id
)
State id of the associated process, determined by OperatorFabric
can be set arbitrarily by the publisher
.
Card Life Management Configuration
With this attributes OperatorFabric know when to display or hide cards, but also if an action is still available for a given card.
Start Date (startDate
)
End Date (endDate
)
Fixes the moment until when OperatorFabric
displays the card. After the card is remove from the GUI feed, see Display Rules for some examples.
Last Time to Decide (lttd
)
Fixes the moment until when a actions
associated to the card are available. After then, the associated actions won’t be displayed or actionable.
Other technical attributes
Publish Date (publishDate
)
Indicates when the card has been registered in OperatorFabric
system. This is a technical information exclusively managed by OperatorFabric
.
Deletion Date (`deletionDate°)
Indicates when the card has been removes from OperatorFabric
system. Technical information manage by OperatorFabric
.
6.1.2. User destined Information of the card
There are two kind of User destined information in a card. Some are restricted to the card format, others are defined by the publisher as long as there are encoded in json
format.
in Card Format
Title (title
)
Summary (summary
)
Custom part
Data (data
)
Determines where custom information is store. The content in this attribute, is purely publisher
choice. This content, as long as it’s in json
format can be used to display details. For the way the details are displayed see below.
6.1.3. Presentation Information of the card
Media (media
)
Some cards can emit a sound when displayed in the feed of the GUI, the id of audio notification is indicated in this attribute.
details (details
)
This attribute is a string of objects containing a title
attribute which is i18n
key and a template
attribute which refers to a template name contained in the publisher bundle. The bundle in which those resources will be looked for is the one corresponding of the version declared in the card for the current publisher. If no resource is found, either because there is no bundle for the given version or there is no resource for the given key, then the corresponding key is displayed in the details section of the GUI.
example:
The TEST
publisher has only a 0.1
version uploaded in the current OperatorFabric
system. The details
value is [{"title":{"key":"first.tab.title"},"template":"template0"}]
.
If the publisherVersion
of the card is 2
then only the title
key declared in the details
array will be displays without any translation, i.e. the tab will contains TEST.2.first.tab.title
and will be empty. If the l10n
for the title is not available, then the tab title will be still TEST.2.first.tab.title
but the template will be compute and the details section will display the template content.
TimeSpans (timeSpans
)
When the simple startDate and endDate are not enough to characterize your process business times, you can add a list of TimeSpan to your card. TimeSpans are rendered in the timeline component as cluster bubbles are as lines depending on your parametrization of the span. This as no effect on the feed content
example 1:
to display the card two times in the timeline you can add two TimeSpan to your card:
{ "publisher":"TSO1", "publisherVersion":"0.1", "processId":"process-000", "startDate":1546297200000, "severity":"INFORMATION", ... "timeSpans" : [ {"start" : 1546297200000}, {"start" : 1546297500000} ] }
In this sample, the card will be displayed twice in the time line. The card start date will be ignored.
example 2:
Instead of the default clustered view, you may want your card to be displayed as a line in the time line.
{ "publisher":"TSO1", "publisherVersion":"0.1", "processId":"process-000", "startDate":1546297200000, "severity":"INFORMATION", ... "timeSpans" : [ {"start" : 1546297200000, "end" : 1546297500000} ] }
6.2. Cards Examples
Before detailing the content of cards, let’s show you what cards look like through few examples of json.
6.2.1. Minimal Card
The OperatorFabric Card specification defines 8 mandatory attributes, but some optional attributes are needed for cards to be useful in OperatorFabric. Let’s clarify those point through few examples of minimal cards and what happens when they’re used as if.
Send to One User
The following card contains only the mandatory attributes.
{ "publisher":"TSO1", "publisherVersion":"0.1", "processId":"process-000", "startDate":1546297200000, "severity":"INFORMATION", "title":{"key":"card.title.key"}, "summary":{"key":"card.summary.key"}, "recipient":{ "type":"USER", "identity":"tso1-operator" } }
This an information about the process process-000
, send by the TSO1
. The title and the summary refers to i18n
keys defined in the associated i18n
files of the publisher. This card is displayable since the first january of 2019 and should only be received by the user using the tso1-operator
login.
Send to several users
Simple case
The following example is nearly the same as the previous one except for the recipient.
{ "publisher":"TSO1", "publisherVersion":"0.1", "processId":"process-000", "startDate":1546297200000, "severity":"INFORMATION", "title":{"key":"card.title.key"}, "summary":{"key":"card.summary.key"}, "recipient":{ "type":"GROUP", "identity":"TSO1" } }
The recipient is here a group, the TSO1
. So all users whoa are member of this group will receive the card.
Complex case
If this card need to be view by a user who is not in the TSO1
group, it’s possible to tune more precisely the definition of the recipient. If the tso2-operator
needs to see also this card, the recipient definition could be(the following code details only the recipient part):
"recipient":{ "type":"UNION", "recipients":[ { "type": "GROUP", "identity":"TSO1"}, { "type": "USER", "identity":"tso2-operator"} ] }
So here, all the users of the TSO1
group will received the INFORMATION
as should the tos2-operator
user.
6.2.2. Regular Card
The previous cards were nearly empty regarding information carrying. In fact, cards are intended to contains more information than a title and a summary. The optional attribute data
is here for that. This attribute is destined to contains any json
object. The creator of the card is free to put any information needed as long as it’s in a json
format.
Full of Hidden data
For this example we will use our previous example for the TSO1
group with a data
attribute containing the definition of a json
object containing two attributes: stringExample
and numberExample
.
{ "publisher":"TSO1", "publisherVersion":"0.1", "processId":"process-000", "startDate":1546297200000, "severity":"INFORMATION", "title":{"key":"card.title.key"}, "summary":{"key":"card.summary.key"}, "recipient":{ "type":"USER", "identity":"tso1-operator" }, "data":{ "stringExample":"This is a not so random string of characters.", "numberExample":123 } }
This card contains some data but when selected in the feed nothing more than the previous example of card happen because there is no rendering configuration.
Fully useful
When a card is selected in the feed (of the GUI), the data is displayed in the detail panel. The way details are formatted depends on template uploaded by Third parties as describe here. To have an effective example without to many actions to performed, the following example will use an already existing configuration.The one presents in the development version of OperatorFabric, for test purpose(TEST
bundle).
At the card level, the attributes in the card telling OperatorFabric which template to use is the details
attributes.
{ "publisher":"TEST", "publisherVersion":"1", "processId":"process-000", "startDate":1546297200000, "severity":"INFORMATION", "title":{"key":"process.title"}, "summary":{"key":"process.summary"}, "recipient":{ "type":"USER", "identity":"tso1-operator" }, "data":{"rootProp":"Data displayed in the detail panel"}, "details":[{"title":{"key":"process.detail.tab.first"}, "templateName":"template1"}] }
So here a single custom data is defined and it’s rootProp
. This attribute is used by the template called by the details
attribute. This attribute contains an array of json
object containing an i18n
key and a template
reference. Each of those object is a tab in the detail panel of the GUI. The template to used are defined and configured in the Third
bundle upload into the server by the publisher.
6.2.3. Displaying Rules
Dates
Dates impact both the feed rendering and the timeline rendering.
In the feed cards are visible based on a collection of filters among which a time filter.
In the time line cards are visible based on a similar filter plus the time line renders the "position" in time of said cards. By default it groups cards at close time in bubbles whom color indicates severity and inner number indicates number of cards.
Start Date (startDate
)
The card is only display after this date is reach by the current time. It’s a mandatory attributes for OperatorFabric cards.
example:
The current day is the 29 january of 2019.
A card with the following configuration "startDate":1548758040000
, has a start date equals to the iso date: "2019-01-29T10:34:00Z". So the operator will see it appearing in it’s feed at 10h34 AM universal time. And if there is no endDate
defines for it, it will stay in the feed indefinitely, so this card should be still visible the 30th january of 2019. Before "10h34 AM universal time", this card was not visible in the feed.
End Date (endDate
)
This optional attribute, corresponds to the moment after which the card will be remove from the feed of the GUI.
example:
Imagine that the current day is still the 29 january of 2019.
The card we are looking after, has the same value for the startDate than in the previous example but has the following configuration for the endDate
: "endDate":1548765240000
. It’s corresponding to "2019-01-29T12:34:00Z" universal time.
So our card is present in the feed between "11h34" and "13h34". Before and after those hours, the card is not available.
Recipients
The attribute recipient
of a card tells to whom it’s sent. It’s value format is an object named recipient
that describe the rule for recipient computation.
The available types are:
-
GROUP
-
USER
-
UNION
-
DEADEND
The simplest way to determine the recipient is to assign the card to a user
or a group
as seen previously in "Minimal Card".
But it’s possible to combine groups and potentially users using UNION
type to have a better control on whom should receive the card.
UNION
For example, if a card is destined to the operators of TSO1
and TSO2
and needs to be also seen by the admin
, the recipient configuration looks like:
"recipient":{"type":"UNION", "recipients":[ {"type":"GROUP","identity":"TSO1"}, {"type":"GROUP","identity":"TSO2"}, {"type":"USER","identity":"admin"} ] }
7. Cards Consultation Service
The User Interface depends on the Cards Consultation service to be notified of new cards and to consult existing cards, both current and archived.
7.1. Archived Cards
7.1.1. Key concepts
Every time a card is published, in addition to being delivered to the users and persisted as a "current" card in MongoDB, it is also immediately persisted in the archived cards.
Archived cards are similar in structure to current cards, but they are managed differently. Current cards are uniquely identified by their id (made up of the publisher and the process id). That is because if a new card is published with id as an existing card, it will replace it in the card collection. This way, the current card reflects the current state of a process instance. In the archived cards collection however, both cards will be kept, so that the archived cards show all the states that a given process instance went through.
7.1.2. Archives screen in the UI
The Archives screen in the UI allows the users to query these archives with different filters. The layout of this screen is very similar to the Feed screen: the results are displayed in a (paginated) card list, and the user can display the associated card details by clicking a card in the list.
The results of these queries are limited to cards that the user is allowed to see, either because they are direct recipient of the card or because they belong to a group that is a recipient of the card. |
7.1.3. Archive endpoints in the card-consultation API
This Archives screen relies on dedicated endpoints in the card-consultation API, as described here.