Skip to content

Data Model

The definition of the data model is independent of the used perspective(s). It is based on object types and relations common to the backend specific database model. It defines how data is read from the backend and how data is pushed to the backend.

Characteristics:

  • Hierarchical tree structure (of related nodes)

  • One distinct root node ("root")

  • Nodes may have several sub nodes ("children")

  • Relations are used to traverse from nodes to sub nodes ("query")

  • Constraints are used to define the right subset of data records ("query")

  • Nodes may have several attributes (persistent, transient) ("attributes")

Nodes

Nodes are representing a backend specific entity in an Insight configuration.

Characteristics:

  • Hierarchical tree structure (of related nodes)

  • One distinct root node ("root")

  • Nodes may have several sub nodes ("children")

  • Relations or queries are used to traverse from nodes to sub nodes

  • Constraints are used to define the right subset of data records

Base properties

The following properties must be set

"name": "Standort"
    "type": "LOCATIONS"
    "title": "Standort",
    "label": "${LOCATION} - ${DESCRIPTION}",
    "query": {...}
"name": "Standort",
    "type": "508:43137:MC",
    "title": "Standort",
    "label": "${508:43105:AB}-${508:43345:AB}"
  • name defines name of the node
    o unique
    o For technical reasons the name must not contain dots (such as package names).
    o is used for standard aggregation of search results (Insight Explorer)

  • type defines backend specific object type

  • title defines label for UI presentation (details (Insight Explorer), header (Insight Mobile))

  • label is used in perspectives to help users identifying the data record

  • ${ATTRIBUTENAME} is dynamically replaced with the value of the attribute with the name ATTRIBUTENAME

  • query is used to describe the subset of data records

query (Maximo)

A node's "query"-section defines the subset of data that will be retrieved (criteria) and how the data will be retrieved (MboSet or Database).

constraint

"constraint" constrains the data set that will be retrieved.

"constraint" is optional in root or child nodes.

If given, the "constraint" will be part of the WHERE-clause, so it has to be valid SQL.

    "root": {
      "name": "pm",
      "type": "PM",
      "query": {
        "constraint": "PARENT IS NULL"
      },

The data set for child nodes is typically constrained by a Maximo relationship.

In cases where relations can't be used, "constraint" comes to the rescue.

Placeholders are used to define the parent's properties.

    "children": [{
      "name": "problemcode",
      "type": "FAILURECODE",
      "query": {
        "constraint": "FAILURECODE='${PROBLEMCODE}'"
      },

relation

"relation" constrains the data set of child nodes to the associated objects.

"relation" must be the name of a Maximo relationship that points from parent's type to child's type.

    "children": [{
      "name": "asset",
      "type": "ASSET",
      "query": {
        "relation": "ASSET"
      },

A child node must provide at least one of "relation" or "constraint".

db

"db" is used to define if data is collected by means of MboSets or by direct database access.

"db" can have one out of three values.

false a node's attribute values as well as the idents leading to it are collected with MboSets
true a node's attribute values as well as the idents leading to it are collected with direct database access
null a node's attribute values are collected with MboSets, but the idents leading to it are collected by direct database access

Full database access:

    "query": {
      "db": true

This setting yields the best performance. The attribute values will be read directly from the database, bypassing the MBO layer entirely.

Use this setting only when

  • you can forgot business logic of the MBO layer

  • all the node's attributes are persistent

Mixed mode:

    "query": {
      "db": null

That's the default case, when "db" is not declared at all.

The attribute values will be collected by means of MboSets, so the MBO layer's business rules will be obeyed.

You can have transient attributes declared.

A parent's child idents, concerning the node in question (or the root idents, if the node is the root node), will be collected with direct database access.

In almost all cases, this strategy leads to the same result as if the idents were collected by MboSets.

MboSet-only:

    "query": {
      "db": false

In this mode, even the idents leading to the node are collected by means of MboSets.

Use this mode if and only if the MBO layer's business rules must be obeyed to determine the proper child set (or root set).

Downloading many data instances with this setting applied will be considerably slower.

orderBy (deprecated)

"orderBy" is supported for backward compatibility reasons, but is considered deprecated.

You should use sortBy to define the order in which siblings are listed.

indexer

"indexer" helps with reconciling the redundant data that are held in elastic search indices.

It is used to traverse the tree bottom up.

A change in an object can affect its parent's child set. In order to reconsider the parent's child set,

the "indexer" hint is needed.

Without defining "indexer", changes to the parent's child set will be reflected only with the next 'full build'

    "children": [{
      "name": "asset",
      "type": "ASSET",
      "query": {
        "relation": "ASSET",
        "indexer": {
          "parentRelation": "ALLWO"
        }
      },
stopandnochildren

Optimizing redundant data and cut off nodes and whole branches can be done with "stop" or "noChildren" in "indexer"

    "children": [{
      "name": "asset",
      "type": "ASSET",
      "query": {
        "relation": "ASSET",
        "indexer": {
          "mode": "noChildren"
        }
      },
  • mode "noChildren" means, that objects for this node will be store in redundant data store (Elastic) but no children.

  • mode "stop" means, that no objects for this node and no children will be stored.

  • mode "stop" in root-node means that this treeConfig wont be indexed at all

parentMapping

"parentMapping" can be used to define foreign keys to parent nodes. This is necessary to create offline objects with subobjects. The foreign key attributes of the child node are replaced after creating the parent object.

Example tree config:

    {
      ...
      "menus": [ {
        "label": "Workorder",
        "action": "create",
        "icon": "icon-plus",
        "actionValues": [{
          "\_node": "workorder",
          "DESCRIPTION": "Static value"
        }]
      }],
      "root": {
        "name": "workorder",
        ...
        "menus": [ {
          "label": "Worklog",
          "action": "create",
          "icon": "icon-plus",
          "actionValues": [{
            "\_node": "worklog",
            "DESCRIPTION": "Static value"
          }]
        }],
        "attributes": [{
          "name": "WONUM",
          "label": "Number",
          "type": "String",
          "readonly": true
        }, {
          "name": "DESCRIPTION",
          "label": "Description",
          "type": "String"
        }, {
          "name": "SITEID",
          "label": "SITEID",
          "type": "String",
          "control": "disabled"
        }],
        "children": [{
          "name": "worklog",
          ...
          "query": {
            ...
            "parentMapping": {
              "RECORDKEY": "WONUM",
              "SITEID": "SITEID"
            }
          },
          "attributes": [
            {
              "name": "DESCRIPTION",
              "label": "Überschrift",
              "type": "String",
              "control": "createOnly"
            },
            {
              "name": "SITEID",
              "label": "SITEID",
              "type": "String",
              "readonly": true
            },
            {
              "name": "RECORDKEY",
              "label": "Arbeitsauftrag",
              "type": "String",
              "readonly": true
            }
          ]
        }]
      }
    }

Root

  • root defines the root node of the data model

  • Except properties loop and query there is no difference between a root node and a child node. For further information see chapter Node properties.

  • query: is used to describe the subset of data records, according to the current use case.

    {
      "name": "locations",
      "root": {
        "query": {
          ...
        }
      }
    }
    

query (OpenJet)

The root node's "query" section is used to define which entities should form the tree's top level elements.

The root query can be defined in the following ways:

1) Unconstraint: Will result in all entities of root's type

        "query": { }

2) By use of a modeled search: Will result in all entities that match the search criteria

        "query": {
            "jetSearch": "508:42315:QU"
        }
  • jetSearches are not allowed to use LibMethods because of their very dynamic behavior!

3) By constraining the root type: Will result in all entities that match the configured constraint.

        "query": {
            "constraint": {
                ...
            }
        }

Children

Children are nodes. For further information see -> chapter Node properties. Root nodes and child nodes are almost the same excluding the following properties:

  • "query" is used to describe the subset of data records (traverse parent  this child node)

  • Configured with a backend specific relation (and/or a constraint and an optional orderBy property (if Maximo))

  • "loop" Node/sub nodes relations may be recursive

loop

Node/sub nodes relations may be recursive.

    "children": [{
            "loop": true,
            "query": "..."
  • "query" is specified as described in the topic below (children - query)

  • "loop" nodes derive their properties (such as attributes and menus sections) from the parent node;

  • Attention : properties derived from parent node must not be redefined

  • Attention : If parent node provides queryParams, then child-data are expected to fulfill queryParam-constraints too, unless omitQueryParams is set to true.

omitQueryParams

Applies to loop nodes only. If set to true, children are not required to fulfill the parent node's queryParam-constraints.

  • Attention: Setting omitQueryParams to true, may cause a security concern. Since the profile constraint is not applied, it can no more be garantueed, that only intended parties can read corresponding data.

query (OpenJet)

The child node's "query" section is used to define which entities should form the parent's child elements.

There are two forms of declaration:

Relation:

In this form, the "query" section has 2 mandatory properties:

"relation" Refers to the association which joins parent type with child type
"direction" Indicates if the association is to be traversed as in the static model ("TOP_DOWN") or reverse ("BOTTOM_UP")

The "query" section has one optional property

"constraint" Restricts the associated child elements to the proper subset
Chain:

You will use this alternative in order to 'skip unwanted intermediate nodes' as e.g. attributed link classes in m:n relations.

In this form there is only one mandatory attribute:

"chain" Array of relations that traverse from parent to child
"query": "{
        "chain": [
            {
                "relation": "508:43149:AS",
                "direction": "TOP_DOWN",
                "constraint": { ... }
            },
            {
                "relation": "508:43151:AS",
                "direction": "TOP_DOWN",
                "constraint": { ... }
            }
        }
    }

Note that:

  • The first relation of a chain must be adjacent with the parent node
  • Consecutive relations of a chain must be adjacent with each other
  • The last relation of a chain must be adjacent with the child node
  • "relation" and "direction" fields are mandatory for all relations of a chain, while "constraint" fields are optional

queryParams

"queryParams" are used to refine constraints. "queryParams" can therefore help to reduce the number of root-records/child-records.

While the query-section's constraint is applied independent of the calling user, queryParams are applied in behalf of the calling user.

The constraining values are obtained from the calling user's profile at runtime.

Syntax

queryParams take one of the following forms:

    "queryParams": {
      "name": name,
      "attribute": attribute
    }

Here name and attribute are to be replaced by the parameter name and the attribute name respectively.

    "queryParams": {
      "and": [
        c1, 
        c2, ...
      ]
    }

Here c1, c2, ... are queryParam-Constraints themselves. The supported logical operators are "and" and "or".

You can nest and/or. The array-length must be at least 2.

Due to backward-compatibility the historical (pre-2.7) syntax is also supported:

    "queryParams": [
      {
        "name": name,
        "attribute": attribute
      }, ...
    ]

If your node not only uses queryParams, but also has a loop child node, then child-data must also fulfill the queryParams constraint!

queryParams-Example-Maximo

    "query": {
      "constraint": "HISTORYFLAG=0 AND STATUS IN ('APPR', 'INPRG')"
    }

    "queryParams": {
      "and": [
        {
          "name": "siteid",
          "attribute": "SITEID"
        },
        {
          "or": [
            {
              "name": "personid",
              "attribute": "OWNER"
            },
            {
              "name": "persongroup",
              "attribute": "OWNERGROUP"
            }
          ]
        }
      ]
    }

Constraints (OpenJet)

Constraints are used to restrict the tree's elements to the proper subset of database records. Constraints can be used in two places:

1) In the root node's "query" section when no "jetSearch" is defined to restrict the root elements.

2) In the child node's "query" section in order to restrict the associated child elements.

    "query": {
        ...
        "constraint": { ... }
    }

Constraints come in two forms:

1) Conditional constraints ("Conditional constraints") as for c1 and c2 where c1 and c2 are constraints themselves

2) Atomar constraints ("Atomar constraints") as for firstname = Peter

Conditional Constraints

The logical operators and, or and not are supported by conditional constraints

    "constraint": {
            "and": [
                { ... },
                { ... }
        ]
    }


    "constraint": {
            "or": [
                { ... },
                { ... }
        ]
    }


    "constraint": {
            "not": {
                ...
            }
        }

The array lenght of "and"/"or" is not restricted to two as in the example, but must be at least two.

For technical reason, "and" and "or" can't be negated with "not".

Atomar Constraints

Atomar constraints take one of the following forms

  • Left operator right
  • Left operator
  • InstanceOf className
  • Relation-constraint

  • The terms left may stand for are attribute expressions
  • The terms right may stand for are literals

Supported binary operators are:

"eq" left equal to right
"ne" left not equal to right
"match" left matches right (Joker-Characters are ? and *)
"lt" left less than right
"le" left less than or equal to right
"gt" left greater than right
"ge"" left greater than or equal to right
"in" left equal to one of the terms in right enumeration
"notIn" left not equal to any of the terms in right enumeration

Supported unary operators are:

"isNull" left undefined
"notNull" left defined
Constraint Fields

Atomar constraints are defined by the following properties:

Operator-Constraints
"attribute" Model-Id of the attribute that forms the left expression
"operator" One of the supported binary or unary operators
"value" Literal that forms the right expression (not needed for unary operators)
InstanceOf-Constraint:
"instanceOf" Model-Id of the class
Relation-Constraint:
"relation" Model-Id of the association which joins the related type
"direction" Indicates if the association is to be traversed as in the static model ("TOP_DOWN") or reverse ("BOTTOM_UP")
"constraint" The constraint that must hold for associated objects. The structure is recursive. Atomar constraints can be used as well as conditional ones.
Constraint Example

Here is a quite comprehensive demo of a child node's constraint:

    "children": [
        {
        "name": "Person",
        "type": "508:40321:MC",
        "query": {
            "relation": "508:44617:AS",
            "direction": "TOP_DOWN",
            "constraint": {
            "and": [
                {
                "attribute": "508:42915:AB",
                "operator": "in",
                "value": [ 10, 20, 30, 40 ]
                },
                {
                "attribute": "508:42235:AB",
                "operator": "eq",
                "value": true
                },
                {
                "or": [
                    {
                    "attribute": "508:40323:AB",
                    "operator": "in",
                    "value": [ "Bernhard", "Marc" ]
                    },
                    {
                    "attribute": "508:40325:AB",
                    "operator": "in",
                    "value": [ "Hanke", "Neblung" ]
                    }
                ]
                }
            ]
            }
        }
    },

SortBy

"sortBy" is used to define the order in which the client should list siblings.

"sortBy" has the following members:

"attribute" mandatory String denotes the attribute which defines the order
"descending" optional boolean, default = false list hi values before low values
"thenBy" optional Map subordinated ordering definition (recursion)

Examples:

    ...
    "sortBy": {
      "attribute": "billingDate",
      "descending": true
    }

    ...
    "sortBy": {
      "attribute": "lastname",
      "thenBy": {
        "attribute": "firstname"
      }
    }

Only persistent attributes are allowed to define the order.

If "sortBy" is not defined, then the order will be derived from the node's label. The order is then defined by the label's persistent attributes that are local to the node.

Advanced properties

insert/create nodes

In some backend systems data base tables have non-canonical names for their key attributes. To enable Insight to present data sets immediately after their creation, it is mandatory to register those key attributes.

    "clientProperties": {
      "IDKEY": "TICKETUID"
    },

Classification (Maximo)

Classification can be used in every node that is configured with a class using classifications.

    "root": {
      ....
      "classification": {
        "enabled": true,
        "insertBefore": <attribute>
      },

List of classification attributes is dynamically inserted before/after the attribute <attribute> in the "attributes":[] Array. (Option "insertBefore"/"insertAfter")

"showClassifier": The classifier attribute is hidden by default. With this boolean property, the classifier can be shown.

Documents

A node of type Documents represents a special kind of child-node.

It enables Insight Mobile clients to

  • capture pictures

  • bind these pictures to its parent node

  • push this data to an upload service

There is a default upload service which performs the following steps (Maximo):

  • Creating of a DOCLINK record

  • Linking this record to the parent node object and

  • Storing the picture to the directory configured in the Maximo System Properties.

With "backendParams" it is possible to pass additional (parent) node specific meta data to the upload service.

"minCount": Number of documents/fotos which have to be uploaded.

"attributes": Attributes that can be filled in for a document. These attributes are transferred to the server when uploading. The names are not allowed to overlap with those from backendParams. See also: node attributes.

    "documents": [
      {
        "name": "foto",
        "label": "Fotos",
        "type": "Foto",
        "backendParams": {
          "OWNERTABLE": "WORKORDER",
          "OWNERID": "${WORKORDERID}",
          "SITEID": "${userData.siteid}"
        },
        "clientProperties": {
          "minCount": 1
        },
        "attributes": [
          {
            "name": "REQUIRED",
            "label": "Required",
            "type": "String",
            "required": true
          }
        ]
      }
    ],

ExcludeExpertSearch

To exclude an node from expert search use the following clientProperty:

    "clientProperties: {
      "excludeExpertSearch": true
    }

LabelWidth

To set a fix label width for the form use the following clientProperty:

    "clientProperties": {
      "labelWidth": "130"
    }

InlineOnly

InlineOnly can be set for nodes which are only used for inline fields. These nodes are not displayed on the UI.

    "inlineOnly": true,

Attributes

Base properties

The following base properties must be configured.

"name" "ATTRIBUTEID" (ATTRIBUTEID specifies the Attribute in the given backend)
"label" "xyz" xyz is used in the detail view to help the user to identify the attribute
"type" Specifies the (Insight specific) data type of the attribute

Types

Attention: Value of "type" must match the type in the backend.

  • "String"

  • "Boolean"

  • "Date"

  • "Text"

  • "Decimal"

  • "Base64" (Maximo only)

  • "Born" Boolean or null.

    "root": {
        "name": "Standort",
          "attributes": [{
            "name": "LOCATION",
            "label": "Standort",
            "type": "String",
            "readonly": true
          }, {
            "name": "DESCRIPTION",
            "label": "Zusammenfassung",
            "type": "String"
          }, {
            "name": "SITEID",
            "label": "Niederlassung",
            "type": "String",
            "hidden": true
        }],
    

Read/write

  • "readonly": Boolean (default false). The form field is disabled and the insight middleware prevents the field from being written.

    o true --> field is disabled
    o false --> field is enabled

To disable, hide or enable at create - see control.

  • "clientProperties.mustWrite": Boolean (default false). Normally, only the changed attributes are sent when saving. With this property, this attribute is always sent.

maxlength, cols, rows

widget: String

  • maxlength of an attribute is defined by its size in the database
  • can be overwritten for specific usecases

widget: textarea`

  • cols and rows can be configured in clientProperties
  • when you define cols you should also define a monospaced font via CSS

include attribute of a subsequent node

Inline:

To Include an attribute of a subsequent node in the detail view of the current node, use the following notation:

"attributes":[{
    "name": "nodename/attributename"
}

Nodes can also be flagged with inlineOnly.

Barcode

To include Barcode reading via Cam (smart phone, tablet, webcam,..) use barcode property

    "attributes": [{
        "name": "LOCATION",
        "label": "Standort",
        "type": "String",
        "barcode": true
    }

Supported barcode types on iOS and Android:

Barcode Type Android iOS
QR_CODE x x
DATA_MATRIX x x
UPC_A x x
UPC_E x x
EAN_8 x x
EAN_13 x x
CODE_39 x x
CODE_93 x
CODE_128 x x
CODABAR x
ITF x x
RSS14 x
PDF_417 x x
RSS_EXPANDED x

Phone

To include tel protocol use the following clientProperty:

    attributes[
    {
      "name": "PHONE",
      ...
      "clientProperties": {
        "phone": true
      }
    ]

The attribute value is passed to the tel:// protocol which starts dialing the given number if there is a phone service available on the client device.

Sms

To include sms protocol use the following clientProperty:

    attributes[
    {
      "name": "PHONE",
      ...
      "clientProperties": {
        "sms": true
      }
    ]

The attribute value is passed to the sms:// protocol which starts the default sms app.

Mail

To include mailto protocol use the following clientProperty:

    attributes[
    {
      "name": "E-Mail",
      ...
      "clientProperties": {
        "mail": true
      }
    ]

The attribute value is passed to the mailto:// protocol which starts the default mail app.

Keypad

Shows a button behind the input control that displays a keypad dialog. The buttons of the keypad can be freely defined. When you click on a button, the text is added to the attribute value. At least the value of the button must be configured. An alternative label, color and delete can also be defined. A keypad can be added to a string attribute.

  • value: Value to add (mandatory)
  • label: to display
  • clear: Clears the whole text. Can be used to replace the whole value.
  • styleClass: Styling the button cell. Can be used to add color to the cell.

"Attribute with komplex dialpad":

{
    "name": "PHONE",
    "label": "Beschreibung",
    "type": "String",
    "control": "enabled",
    "clientProperties": {
        "keypad": {
            "rows": [
                [ { "value": "1" }, { "value": "2" }, { "value": "3" } ],
                [ { "value": "4" }, { "value": "5" }, { "value": "6" } ],
                [ { "value": "7" }, { "value": "8" }, { "value": "9" } ],
                [
                    {
                        "label": "DE",
                        "value": "+49 ",
                        "clear": true,
                        "styleClass": "bg-color-light-blue"
                    },
                    {
                        "value": "0"
                    },
                    {
                        "label": "Local",
                        "value": "+49 6201 503 ",
                        "clear": true,
                        "styleClass": "bg-color-light-blue"
                    }
                ]
            ]
        }
    }
},

Value lists

  • "options": Values

    • "dictionary" Values can be listed directly

    • "hint" Values retrieved from a backend specific dictionary

  • "selectFromTree" : Values of attributes retrieved from node items of another Insight Config configuration

options

dictionary: Values can be listed directly

    "options": {
      "dictionary": [
        {
          "label": "true",
          "value": "J"
        },
        {
          "label": "false",
          "value": "N"
        },
        {
          "label": "null",
          "value": "LEER"
        }
      ]

hint: Values of a Domain can be included.

    {
    "name": "DESCRIPTION",
    "label": "DESCRIPTION",
    "type": "String",
    "options": {
        "hint": "VMMANUFACT"
    }
    },
    {
    "name": "TOTALCOST",
    "label": "TOTALCOST",
    "type": "Decimal",
    "options": {
        "hint": "TICKETPRIORITY"
    }
    }

hint: Values of a static Thesaurus can be included.

    {
    "name": "500:293:AB",
    "label": "DESCRIPTION",
    "type": "String",
    "options": {
        "hint": "thesaurus={\"name\":\"Priority\"}"
        }
    }

Values of a dynamic Thesaurus must be included by defining the values as child nodes.

    "children": [
        {
        "name": "reportattributeval",
        "type": "500:11453:MC",
        "icon": "icon-list",
        "label": "${500:293:AB}",
        "query": {
            "chain": [...]
        },
        "attributes": [
            {
            "name": "500:293:AB",
            "label": "",
            "type": "String"
            }
        ]
        }
    ]

To access these values within option, the hint needs to address the child node and the attribute, separated by a semicolon(';')

    {
    "name": "500:11542:AB",
    "label": "Value",
    "type": "String",
    "control": "enabled",
    "options": { "hint": "reportattributeval;500:293:AB" }
    }

SelectFromTree

  • "selectFromTree": Values can be node items of another Insight Config configuration
  • Attributes with selectFromTree can't be edited manually. This is the default behavior since 2.13.1.
    • The default behavior can be overridden by
      • setting the global client-config-property "selectFromTreeEnabled"
      • setting the property "enabled" on "selectFromTree" (from Version 2.14)
  • Presents node instances of src Insight Config configuration ("tree") in a selection view

    • "tree": tree to select from
    • "node": node to select from (currently only the root node is supported)
    • "attribute": attribute of root node (in the referenced configuration specified in „tree")
    • "search": search name to use when selecting. The search must be defined in the given "tree". See: searches.
    • "autofill": Array of attributes to be copied if validation succeed
      • "src": name of attribute (in the referenced configuration specified in „tree")
      • "dst": name of attribute in this node (in the enclosing configuration)
    • "filter": Key value mapping to filter the items to select.
    • "enabled": true, false. Activate manual inputs
    • "deep": true, false. Activate deep tree selection. Only the records specified in "node" can be selected. The selection starts at the root list by default.
      • "contextId": (optional) If the last position in the "selectFromTree-tree" is known at the current record, it can be displayed again. "contextId" must be set to the uniqueId of the record in the "selectFromTree-tree".(last part of the path) Full example below. The parent hierarchy can be resolved online and offline. Online: The search-index is used, offline the downloaded data.
      • "contextNode": Alternative node to display.

        {
        "name": "CRAFT",
        "label": "Gewerk",
        "type": "String",
        "selectFromTree": {
            "tree": "craft",
            "node": "Craft",
            "attribute": "CRAFT",
            "autofill": [{
            "src": "STANDARDRATE",
            "dst": "PAYRATE"
            }]
        }
        }
        
  • Example with filter:

        "selectFromTree": {
        "tree": "failurelist-problem",
        "node": "failurelist",
        "attribute": "FAILURECODE",
        "filter": {
            "PARENT": "${FAILURELIST1}"
        }]
        }
    
  • Full example with deep, contextId and autofill:

        {
        "name": "LOCATION",
        "label": "Standort",
        "type": "String",
        "clientProperties": {
            "labelHidden": true,
            "clear": true
        },
        "selectFromTree": {
            "tree": "test-locations",
            "node": "Standort",
            "attribute": "LOCATION",
            "deep": true,
            "contextNode": "Standort",
            "contextId": "${LOCATIONSIDTEMP}",
            "autofill": [{
            "src": "LOCATIONSID",
            "dst": "LOCATIONSIDTEMP"
            }]
        }
        },
        {
        "name": "LOCATIONSIDTEMP",
        "label": "StandortId",
        "type": "String",
        "formField": true,
        "clientProperties": {
            "
        ": {
            "js": "if(!value){setValue(getValueForName(&#39;LOCATIONS/LOCATIONSID&#39;))}"
            }
        }
        },
        {
        "name": "LOCATIONS/LOCATIONSID",
        "label": "StandortId",
        "type": "String"
        }
    

Field validation

Required

"required":true

The flag enables the "required" field feature.

The client checks if there is data set in the corresponding input field, decorates the field according to the state (filled/not filled) and prevents a push data operation if such a required field is not filled (and presents the error state via decoration and message to the user).

    "attributes": [
        {
          "name": "LOCATION",
          "label": "Standort",
          "type": "String",
          "required": true
        }]

ExistsValidator

This feature is supported only by insight-mobile. The data to be checked must be downloaded first. Validation overrides existsValidator but can be compensated by findInTree.

"existsValidator" validates if user input matches a given attribute value of a root node instance in another Insight Config configuration ("tree").

  • "tree" specifies source Insight Config configuration
  • "attribute" attribute of root node (in the referenced configuration specified in „tree")
  • "autofill": Array of attributes to be copied if validation succeeds
    • "src": name of attribute (in the referenced configuration specified in „tree")
    • "dst": name of attribute in this node (in the enclosing configuration)
  • "filter": Key value mapping to filter the items to select.

Validation

ClientProperty 'validation' provides a set of functions and params to build an interactive input flow (focus - input - validate - warn/error/shift focus -..).

These params and functions can be used inside a js code snipped which is defined in the js section of the 'validation' ClientProperty.

Trigger:

  • Each change to the corresponding form field will cause the execution of the defined code snipped

  • Each time the form is saved will cause the execution of each defined 'validation' of the enclosing node (see Parameter "save")

Params:

  • value represents the actual value

  • attribute JS-Attribute object

  • attributes all JS-Attribute objects of current detail view

  • save Boolean: Indicates whether validation is performed due to saving or due to user input.

  • object server representation of the current object; current changes are not reflected;

  • isNew Boolean: Indicates whether the record is to create

  • userData Properties of the logged in user. (Working with variables/values)

  • nfcResult Read NFC result

Functions:

  • valid marks the input field as valid: e.g. valid();

  • warn presents a given warning to the user but does not prevent the data set to be stored, e.g.: warn('Input exceeds max value. Proceed?');

  • invalid presents a given error message to the user and prevents data from being storde, e.g.: invalid('Not valid ...');

  • attributeForName retrieves attribute object by its name. e.g.: var attribute = attributeForName('DESCRIPTION');

  • getValueForName retrieves attribute value by its name (replaces valueForAttributeName). e.g.: var value = getValueForName('DESCRIPTION');

  • next shifts focus to the next editable field. To shift the focus to the attribute with a particular name call next with parameter_,_ e.g.: next('DESCRIPTION');

  • validAndNext marks the input field as valid and jumps to the next field; e.g. validAndNext(); or validAndNext('DESCRIPTION');

  • findInTree Searches in other tree by filter; e.g. findInTree('treename', filterMap).then(callback); The parameter of the callback function is: firstRecords (see code example below) !!! It is absolutely necessary to call valid, invalid or validAndNext in the callback function !!!

  • findInTree can also use a defined search of the destination tree. This only works offline; e.g. findInTree('treename', filterMap, 'searchString, 'nodename', 'searchname').then(callback); The callback function got a second parameter: searchResult (all found rows of the offline search model)

  • selectFromTree can be called to display the dialog from the validation (insight-mobile only). selectFromTree must be configured at the attribute. searchString, filter and openSingleSearchResult can be used in the options. oneTime can also be configured to use openSingleSearchResult and filter only on the first search. e.g. see below.

  • setValue Sets the value of the current field; e.g. setValue('Foo');

  • setValueForName Sets the value of given field; e.g. setValueForName('DESCRIPTION', 'Foo');

  • sound Plays a sound. There are two default sound files: positive and negative; e.g. sound('positive'); Own sound files can be integrated via static-content. e.g. sound('static-content/my-sound.mp3');

  • remote.validate('middleware/check', {value: value}); -- calls the remote script with the given data-object and executes valid()/invalid() depending on the success (HTTP-Status 200) or failure (HTTP-Status 500) of the script

  • remote.action('middleware/uuid').then((data) =\> { setValue(data.uuid); }); -- calls the remote script with the given data-object, you need to handle the returned object/failure in the method through a promise

  • setReadonly Sets UI control readonly or not. e.g. setReadonly(true);

  • setReadonlyForName Sets UI control readonly or not for attribute name. e.g. setReadonlyForName('DESCRIPTION', true);

    "clientProperties": {
      "validation": {
        "js": "value == 10 ? valid() : invalid(&#39;Not 10!&#39;);"
      }
    }
    



    "clientProperties": {
      "validation": {
        "js": "if(!save){attributeForName(&#39;FR2CODE&#39;).value = undefined;} if(value != undefined &amp;&amp; value != &#39;&#39;){ next() }"
      },
      "attributeControl": {
        "js": "attribute.readonly = valueForAttributeName(&#39;PROBLEMCODE&#39;) == undefined || valueForAttributeName(&#39;PROBLEMCODE&#39;) == &#39;&#39;; attribute.styleClass = attribute.readonly ? &#39;&#39; : &#39;bg-color-light-red&#39;"
      }
    }



    "clientProperties": {
      "validation": {
        "js": "findInTree(&#39;person&#39;, {PERSONID: value}).then(function(firstRecords){ firstRecords.length \&gt; 0 ? validAndNext() : invalid(&#39;Not found&#39;) })"
      }
    }



    "selectFromTree": {
        "tree": "asset-flat",
        "node": "asset",
        "attribute": "ASSETNUM",
        "autofill": [{
            "src": "LOCATION",
            "dst": "LOCATION"
        }]
    },
    "clientProperties": {
      "validation": {
        "js": "if(!save){var options = { searchString: '*', filter: [{ attribute: 'ASSETNUM', value: assetNum }], openSingleSearchResult: true, oneTime: true, }; selectFromTree(options);}"
      }
    }

AttributeControl

ClientProperty "attributeControl" provides a set of functions and params to set the attribute properties dynamically (see Field validation - validation). The attributeControl-Function can also be used at node configurations.

Trigger:

  • Each change to one of the form fields, having validation or attributeControl, will cause the execution of each defined code snipped

  • On form creation

Paramters and functions are much the same as in the 'validation' section except the next()/validAndNext() functions. These are not accessible during execution of attributeControl.

Params:

  • value represents the actual value

  • attribute JS-Attribute object

  • attributes all JS-Attribute objects of current detail view

  • save Boolean: Indicates whether validation is performed due to saving or due to user input.

  • object server representation of the current object; current changes are not reflected;

  • isNew Boolean: Indicates whether the record is to create

  • userData Properties of the logged in user. (Working with variables/values)

  • onInit Boolean: Indicates whether the form is in initialization

Functions:

  • valid marks the input field as valid: e.g. valid();

  • warn presents a given warning to the user but does not prevent the data set to be stored, e.g.: warn('Input exceeds max value. Proceed?');

  • invalid presents a given error message to the user and prevents data from being storde, e.g.: invalid('Not valid ...');

  • validForName marks the input field as valid: e.g. valid('DESCRIPTION');

  • warnForName presents a given warning to the user but does not prevent the data set to be stored, e.g.: warn('Input exceeds max value. Proceed?', 'DESCRIPTION');

  • invalidForName presents a given error message to the user and prevents data from being storde, e.g.: invalid('Not valid ...', 'DESCRIPTION');

  • attributeForName retrieves attribute object by its name. e.g.: var attribute = attributeForName('DESCRIPTION');

  • getValueForName retrieves attribute value by its name (replaces valueForAttributeName). e.g.: var value = getValueForName('DESCRIPTION');

  • setValue Sets the value of the current field; e.g. setValue('Foo');

  • setValueForName Sets the value of given field; e.g. setValueForName('DESCRIPTION', 'Foo');

  • sound Plays a sound. There are two default sound files: positive and negative; e.g. sound('positive'); Own sound files can be integrated via static-content. e.g. sound('static-content/my-sound.mp3');

  • remote.validate('middleware/check', {value: value}); -- calls the remote script with the given data-object and executes valid()/invalid() depending on the success (HTTP-Status 200) or failure (HTTP-Status 500) of the script

  • remote.action('middleware/uuid').then((data) =\> { setValue(data.uuid); }); -- calls the remote script with the given data-object, you need to handle the returned object/failure in the method through a promise

  • setReadonly Sets UI control readonly or not. e.g. setReadonly(true);

  • setReadonlyForName Sets UI control readonly or not for attribute name. e.g. setReadonlyForName('DESCRIPTION', true);

  • setReadonlyAll Sets UI control readonly for all attributes or not. e.g. setReadonlyAll(true);

    "attributeControl": {
      "js": "attribute.readonly = valueForAttributeName('PROBLEMCODE') == undefined || valueForAttributeName('PROBLEMCODE') == ''; attribute.styleClass = attribute.readonly ? '' : 'bg-color-light-red'"
    }
    
  • calcSelectFromTree SelectFromTree can be activated for the current attribute.

    "attributeControl": {
      "js": "calcSelectFromTree({ tree: 'valuelist-select', node: 'root', attribute: 'valueVarchar' });"
    }
    
  • getParentValueForName: Gets an attribute of the parent object

{
    "attributeControl": {
        "js": "return getParentValueForName('name');"
    }
}

Assignment

The assignment function fills the given attribute dynamically with a value when the specified hook is triggered.

  • "assignment"
    • "type": specifies the function to be called
      • "text": assigns a value (see chapter Working with variables/values)
    • "value": formatted String with variables (see chapter Working with variables/values)
    • "when": specifies the trigger
      • "afterRead" after reading the data
      • "beforeWrite": before sending back to the server
      • "onSave": save button pressed

    "assignment": {
      "type": "text",
      "when": "onSave",
      "value": "Hallo ${WONUM}, ${appParams.standort}, ${userData.personid} - ${func.now}"
    }

FormField

An attribute signed as formField creates a field on a detail page which does not refer to an attribute in the backend.

  • Insight Middleware ignores such fields.

  • Insight Client uses these fields like other attributes.

    {
      "name": "WORKORDERID\_BLAA",
      "formField": true,
      "label": "IDtemp",
      "type": "String"
    },
    {
      "name": "WORKORDERID\_BLAA2",
      "formField": true,
      "label": "IDtemp2",
      "type": "String",
      "assignment": {
        "value": "${DESCRIPTION}",
        "when": "afterRead",
        "type": "text"
      }
    },
    {
      "name": "DESCRIPTION",
      "label": "Beschreibung",
      "type": "String",
      "assignment": {
        "value": "${WORKORDERID\_BLAA}-${WORKORDERID\_BLAA2}",
        "when": "onSave",
        "type": "text"
      }
    }.
    

ExcludeExpertSearch

To exclude an attribute from expert search use the following clientProperty:

    "clientProperties": {
      "excludeExpertSearch":true
    }

Format

Attributes can be formatted with a pattern. The format only affects the display value and the node label.

  • Date:
    • Pattern documentation can be found at java SimpleDateFormat
        {   
            "name": "REPORTDATE",   
            "label": "Date",    
            "type": "Date",     
            "readonly": true,   
            "format": "pattern:&#39;dd.MM.yyyy HH:mm:ss&#39;"   
        }
  • Decimal:
    • Pattern documentation can be found at java NumberFormat
        {   
            "name": "VALUE",    
            "label": "Decimal", 
            "type": "Decimal",  
            "readonly": true,   
            "format": "pattern:&#39;#0.00&#39;,locale:&#39;de&#39;"     
        }

Date

Attributes of type date open a special date picker UI when clicked. That datepicker UI is available on web, mobile and electron. Along with the datepicker UI for attributes of type date, additional features are available:

Min / Max

You can specify a valid range in which a user can pick his date. There are several options.

    {
        "name": "CREATEDATE",
        "label": "My Date Example",
        "type": "Date",
        "clientProperties": {
        "min": [2019, 6, 3],
        "max": [2019, 6, 28]
      }
    }

Instead of fixed date boundaries, you may also specify min as an Integer, relative to today. The following example will start the valid pick range 15 days before today.

    {
        "name": "CREATEDATE",
        "label": "My Date Example",
        "type": "Date",
        "clientProperties": {
        "min": -15,
        "max": [2019, 6, 28]
      }
    }

Setting max to true will set the value to today, false removes any limits.

Disabling dates

You are also able to disable specific dates in the datepicker. To disable a list of specific dates, use the following notation:

    {
        "name": "CREATEDATE",
        "label": "My Date Example",
        "type": "Date",
        "clientProperties": {
        "disable": [[2019, 6, 10], [2019, 6, 11]]
      }
    }

If you want to specific weekdays (Mondays, Thursdays,...) you can use the following notation:

    {
        "name": "CREATEDATE",
        "label": "My Date Example",
        "type": "Date",
        "clientProperties": {
        "disable": [1, 4, 7]
      }
    }

Instead of listing all specific dates to disable, you are also able to list the complete range for disabled dates:

    {
        "name": "CREATEDATE",
        "label": "My Date Example",
        "type": "Date",
        "clientProperties": {
          disable: [
          { from: [2016,2,14], to: [2016,2,27] }
        ]
      }
    }

DirtyCheck

Include or exclude from dirty check of detail pages. The dirty check shows a dialog if a user wants to leave a page and attributes are still changed.

  • Include: Is used to include attributes with settings like "formField".

  • Exclude: Is used to exclude attributes with predifined values from settings like "attributeControl".

    {
      "name": "myfield",
      "type": "String",
      "formField": true,
      "clientProperties": {
        "dirtyCheck": "include"
      }
    },
    {
      "name": "myfield",
      "type": "String",
      "clientProperties": {
      "dirtyCheck": "exclude",
      "attributeControl": {
        "js": "setValue(&#39;Initial value&#39;);"
        }
      }
    },
    

MustWrite

"mustWrite" Is only working if the default save api is used, no "saveAction".

  • true: Attribute is written on save, even if the value is not changed.

  • false: Attribute is never written on save.

    {
      "name": "myfield",
      "type": "String",
      "formField": true,
      "clientProperties": {
        "mustWrite": "false"
      }
    },
    

Derived Attributes

Derived Attributes do not exist within your EAM, but can be derived from them.

Derived attributes are defined in a node's "attributes"-section together with their normal counterparts.

Attribute's properties like "name", "label" or "section" apply as usual.

Derived attributes must be of type "String" and are "readonly" by nature.

A derived attribute is distinguished from an EAM-attribute by its nested "derived"-element.

    "attributes": [
      ...
      {
        "label": "mylabel",
        "name": "myname", "derived"  : {
        ...

Derived Date Pattern Attributes

Derived Date Pattern Attributes can be used to format dates in a customized form.

They are based on an attribute of type "Date". That date attribute must be declared as a sibling EAM attribute.

The "pattern"property defines how the date value is formatted.

A Date Pattern Attribute is defined as followed

    {
      "name": "REPORT\_KW",
      "label": "Erstellt KW",
      "type": "String",
      "derived": {
        "pattern": "YYYY/ww",
        "attribute": "REPORTDATE"
    }
    }

The pattern's rules are explained here.

Derived Regex Attributes

Derived Regex Attributes can be used to extract parts of other attributes.

They are based on an attribute of type "String". That string attribute must be declared as a sibling EAM attribute.

The regex defines how the resulting value is obtained from the actual attribute's value.

With the optional replacement you can empower regular expressions even more.

A Regex Attribute is defined as followed

    {
      "name": "location\_part4",
      "label": "Part4 of Location",
      "type": "String",
      "derived": {
        "regex": "([^-]\*-){3}([^-]\*)-",
        "attribute": "LOCATION"
      }
    }

The nested properties "regex" and "attribute" are mandatory for derived regex attributes.

"regex" denotes a so called extended regular expression as defined e.g. here.

"attribute" denotes the name of the actual EAM attribute.

The nested property "replacement" is optional. Unless given the resulting value is that of the right most group in "regex".

If the regex does not match, the resulting value will be empty.

In the example above the regex attribute's value is derived from EAM's attribute LOCATION.

The extracted part is the text between the third and fourth dash.

Otherwise, if "replacement" is given, then the value is the "replacement" property, where $1, $2 etc are replaced by the captured groups.

If the replacement shall contain the dollar-sign or the backslash literally, it must be escaped by Backslash ().

Note that JSON-Syntax requires the backslash itself to be escaped by another backslash.

Suppose the EAM attribute x has value "abc/pqr/xyz" and the regex attribute is defined like so

    "derived": {
      "regex": "(.\*)/(.\*)/(.\*)",
      "attribute": "x",
      "replacement": "$3 \\$ $1"
    }

The derived value would then be "xyz $ abc".

Derived Replace Attributes

Derived Replace Attributes can be used to compose values from other values.

The "replace" property defines how the value gets composed.

The syntax is the same as for a node's "label".

    "derived": {
      "replace": "${LASTNAME}, ${FIRSTNAME}"
    }