.. _app-development:

App development reference
=========================

This page lists the specifications for apps and groups beyond what is already
required for .lf state machines.

Ports
+++++

The top level state machine for all apps must contain the two ports `Success` and
`Error`.  The choice of ports for all nested states is up to the app developer.
Exception: In groups, any child states that are marked as `container` must also
use the ports `Success` and `Error`.

.. _client-data:

Client Data
+++++++++++

The following fields of client-data are specific to app development. Required
fields are **bold**

* ``type`` **"app" | "group"**
* ``name`` **String**
* ``color`` String
* ``tags`` String[]
* ``image`` String
* ``requiredParameters`` Object[] -- An array of objects which contain source
  parameters defined by

  - ``source``: The name of the parameter in the source
  - ``localParameter``: The name of the parameter as it is used in the state machine
* ``contextMenu`` Script -- The definition of steps to configure the app, refer
  to :ref:`context-menu` for a detailed explanation
* ``components`` Script -- Custom components used in the app, refer to
  :ref:`components` for more information
* ``hiddenInLibrary`` Bool

These fields are only used in apps of type ``group``:

* ``containers`` **String[][] | Object[]**

.. caution::
  The following fields are used for experimental features that may not continue to
  be supported (also only in groups):

  * ``executionDashboard``

Experimental Features
+++++++++++++++++++++

The following group features are experimental and not officially supported:

Wrapper Groups
--------------

Groups can be specified to programmatically wrap any of their child apps with
another group. To do this, specify the ``containers`` property in client data
as an array of objects with the schema ``{String[] path; String wrapper;}``
The value of the field ``wrapper`` must be the name of an existing group.

Example app
~~~~~~~~~~~

.. code-block:: lf

  WrappingGroup {
    port Success true
    port Error false

    clientData {
      type: "group";
      containers: [{path: ["group_body"]; wrapper: "ChildGroup"}];
      name: "Wrapping Group";
      color: "darkgray";
      }@;
    }

    [...]
  }

Behavior
~~~~~~~~

* When an app is inserted into a group's container that has a wrapper specified
  the app automatically appears with the specified wrapper around it. This also
  applies to the case where the app is nested inside of other groups within the
  wrapping group.

* This wrapper cannot be manually (re)moved, however clicking on it will open
  the context menu to configure parameters.

* If the wrapped skill is deleted or moved outside of the wrapping group, the
  wrapper automatically disappears again.

Execution Dashboard
-------------------

The execution dashboard is an experimental feature that allows app developers
to show live information during task execution in desk. To implement an
execution dashboard, add the optional field ``executionDashboard`` to your group
app's ``clientData`` structure. Just like the ``contextMenu`` field, the contents
must be HTML markup and can embed the resources that are declared in the
``components`` field. Analogously to how the contents of the context menu must be
wrapped in ``<step>`` tags, the contents of the the execution dashboard must be
wrapped in a ``<execution-dashboard>`` tag.

Example app
~~~~~~~~~~~

.. code-block:: lf

  DashboardGroup {
    port Success true
    port Error false

    clientData {
      type: "group";
      containers: [["group_body"]];
      name: "Dashboard Group";
      color: "darkgray";
      components: @{
        <component name="test-component">
          <template src="groupy/test.html"></template>
          <script src="groupy/test.js"></script>
        </component>
      }@;
      executionDashboard: @{
        <execution-dashboard id="test-dashboard" name="My Dashboard">
            <test-component></test-component>
        </execution-dashboard>
      }@;
    }

    [...]
  }

Behavior
~~~~~~~~

* When a task is executed that contains a group with an execution dashboard
  specified, an execution dashboard panel will appear in the location otherwise
  occupied by the library drawer.

* At any given time, only the execution dashboards of direct parents of the
  currently executing app can be shown in the panel.

* By default the bottom-most group's dashboard will be focused. By clicking on
  the tab labels, the operator can switch to a different one. This selection
  will be remembered as long as that dashboard is in execution scope.

* Focus switches automatically to track the execution.

* It is possible to add a `name` attribute to your `<execution-dashboard>` tag
  in order to customize the label that appears on the tabs. This may be useful
  for distinguishing between multiple dashboards of a single group. Otherwise
  the group name appears.

* The height of the dashboard is fixed, and if the contents are larger there
  will be a scroll bar.
