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 the 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 typetitle
: 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 ATTRIBUTENAMEquery
: 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}'"
},
}
]
dynamicConstraint¶
dynamicConstraint
can be used to add a constraint from the database. The WHERE
statement from the database is appended to the constraint using AND
. The constraint must be chosen on the mobile root list. This is done by a selectFromTree
. The selectFromTree.attribute
must match backend.primary
. There are some restrictions that apply to dynamicConstraint
:
- Index search cannot apply the where statement, so it is not supported. Please use searches
- Offline search cannot apply the where statement, so you can find all downloaded entries.
- Insight Mobile only
- Maximo backend only
- Root nodes only
{
"name": "root-node",
"query": {
"constraint": "...",
"dynamicConstraint": {
"ui": {
"selectFromTree": {
"tree": "where-configs",
"node": "config",
"attribute": "WHERE_CONFIG_ID"
}
},
"backend": {
"table": "WHERE_CONFIG",
"primary": "WHERE_CONFIG_ID",
"where": "WHERE_CLAUSE"
}
}
}
}
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:
- Unconstrained: Will result in all entities of root's type
"query": { }
- 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!
-
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 aconstraint
and an optionalorderBy
property (if Maximo))
- Configured with a backend specific
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 asattributes
andmenus
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 fulfillqueryParam
-constraints too, unlessomitQueryParams
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
anddirection
fields are mandatory for all relations of a chain, whileconstraint
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. Example:
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:
- In the root node's
query
section when nojetSearch
is defined to restrict the root elements. - In the child node's
query
section in order to restrict the associated child elements.
"query": {
"constraint": { ... }
}
Constraints come in two forms:
-
Conditional constraints ("Conditional constraints") as for c1 and c2 where c1 and c2 are constraints themselves
-
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 length of and
/or
is not restricted to two as in the example, but must be at least two. For technical reason, and
and or
cannot 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. Since version 31 it is also possible to use inline-attributes. If you use inline-attributes then it could be necessary to use qualified names for attributes in constraint to avoid ambiguous column names. Otherwise sql-errors could occur. If inline attributes are used in label and error "no leftJoinOn" occurs than explicity use sortBy to avoid this error.
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.
"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}"
},
"minCount": 1,
"attributes": [
{
"name": "REQUIRED",
"label": "Required",
"type": "String",
"required": true
}
]
}
],
- Note: The document-upload can also be specified at an attribute (see here).
ExcludeExpertSearch¶
To exclude an node from expert search use the following configuration:
"excludeExpertSearch": true
LabelWidth¶
To set a fix label width for the form. (Works in the new client only with labelBeside)
{
"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.FileUpload
"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
}
]
}
FileUpload¶
- This type can be used to bind the Documents upload to an attribute.
{
"name": "FILE",
"label": "File",
"type": "FileUpload",
"formField": true,
"documentName": "fileupload",
}
- documentName refers to the object of the objects array with the given name fileupload.
Read/write¶
-
readonly
: Boolean (defaultfalse
). The form field is disabled and the insight middleware prevents the field from being written.o
true
--> field is disabled ofalse
--> field is enabled
To disable, hide or enable at create - see control.
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
androws
can be configured- when you define
cols
you should also define a monospaced font via CSS
- when you define
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 the ability to read barcodes via Cam (smartphone, tablet, webcam, ...) use the barcode
property. Example:
"attributes": [
{
"name": "LOCATION",
"label": "Standort",
"type": "String",
"barcode": true
}
]
Supported barcode types:
Barcode Type | Android | iOS | Browser |
---|---|---|---|
QR_CODE | x | x | |
DATA_MATRIX | x | x | |
UPC_A | x | x | x |
UPC_E | x | x | |
UPC_C | x | ||
EAN_8 | x | x | x |
EAN_13 | x | x | x |
CODE_32 | x | ||
CODE_39 | x | x | x |
CODE_93 | x | x | |
CODE_128 | x | x | x |
CODABAR | x | x | |
ITF | x | x | |
RSS14 | x | ||
PDF_417 | x | x | |
RSS_EXPANDED | x | ||
I2of5 | x | ||
2of5 | x |
Phone¶
To include tel protocol
use the following notation:
"attributes": [
{
"name": "PHONE",
"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 notation:
"attributes": [
{
"name": "PHONE",
"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 notation:
"attributes": [
{
"name": "E-Mail",
"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 displayclear
: 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 complex dialpad example:
{
"name": "PHONE",
"label": "Beschreibung",
"type": "String",
"control": "enabled",
"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
: Valuesdictionary
: Values can be listed directlyhint
: 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)
- The default behavior can be overridden by
- Presents node instances of src Insight Config configuration (
tree
) in a selection viewtree
: tree to select fromnode
: node to select from (currently only the root node is supported)attribute
: attribute of root node (in the referenced configuration specified intree
)search
: search name to use when selecting. The search must be defined in the giventree
. See: searches.autofill
: Array of attributes to be copied if validation succeedsrc
: name of attribute (in the referenced configuration specified intree
)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 inputsdeep
: true, false. Activate deep tree selection. Only the records specified innode
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 theselectFromTree-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",
"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,
"validation": {
"js": "if(!value){setValue(getValueForName('LOCATIONS/LOCATIONSID'))}"
}
},
{
"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 configurationattribute
attribute of root node (in the referenced configuration specified intree
)autofill
: Array of attributes to be copied if validation succeedssrc
: name of attribute (in the referenced configuration specified intree
)dst
: name of attribute in this node (in the enclosing configuration)
filter
: Key value mapping to filter the items to select.
Validation¶
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
.
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 Parametersave
)
Params:
value
represents the actual valueattribute
JS-Attribute objectattributes
all JS-Attribute objects of current detail viewsave
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 createuserData
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 (replacesvalueForAttributeName
). 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();
orvalidAndNext('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 callvalid
,invalid
orvalidAndNext
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
andopenSingleSearchResult
can be used in the options. oneTime can also be configured to useopenSingleSearchResult
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 executesvalid()
/invalid()
depending on the success (HTTP-Status 200) or failure (HTTP-Status 500) of the scriptremote.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 promisesetReadonly
: 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);
"validation": {
"js": "value == 10 ? valid() : invalid('Not 10!');"
}
"validation": {
"js": "if(!save){attributeForName('FR2CODE').value = undefined;} if(value != undefined && value != ''){ next() }"
},
"attributeControl": {
"js": "attribute.readonly = valueForAttributeName('PROBLEMCODE') == undefined || valueForAttributeName('PROBLEMCODE') == ''; attribute.styleClass = attribute.readonly ? '' : 'bg-color-light-red'"
}
"validation": {
"js": "findInTree('person', {PERSONID: value}).then(function(firstRecords){ firstRecords.length > 0 ? validAndNext() : invalid('Not found') })"
}
"selectFromTree": {
"tree": "asset-flat",
"node": "asset",
"attribute": "ASSETNUM",
"autofill": [{
"src": "LOCATION",
"dst": "LOCATION"
}]
},
"validation": {
"js": "if(!save){var options = { searchString: '*', filter: [{ attribute: 'ASSETNUM', value: assetNum }], openSingleSearchResult: true, oneTime: true, }; selectFromTree(options);}"
}
isChanged
: Checks whether the attribute value has changed.
"attributeControl": {
"js": "if(isChanged()){/* do your code */}"
}
isChangedForName
: Checks whether the value of another attribute has changed.
"attributeControl": {
"js": "if(isChangedForName('other-attribute-name')){/* do your code */}"
}
translate
: Translates text with or without parameters e.g. translate('example') or translate('example_with_parameter', {parameter: 'with parameter'});
AttributeControl¶
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
Parameters 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 valueattribute
: JS-Attribute objectattributes
: all JS-Attribute objects of current detail viewsave
: 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 createuserData
: 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 (replacesvalueForAttributeName
). 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 executesvalid()
/invalid()
depending on the success (HTTP-Status 200) or failure (HTTP-Status 500) of the scriptremote.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 promisesetReadonly
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');"
}
}
isChanged
: Checks whether the attribute value has changed.
"attributeControl": {
"js": "if(isChanged()){/* do your code */}"
}
isChangedForName
: Checks whether the value of another attribute has changed.
"attributeControl": {
"js": "if(isChangedForName('other-attribute-name')){/* do your code */}"
}
translate
Translates text with or without parameters e.g.translate('example')
ortranslate('example_with_parameter', {parameter: 'with parameter'});
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 calledtext
: assigns a value (see chapter Working with variables/values)
value
: formatted String with variables (see chapter Working with variables/values)when
: specifies the triggerafterRead
after reading the databeforeWrite
: before sending back to the serveronSave
: 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 notation:
"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 javaSimpleDateFormat
{
"name": "REPORTDATE",
"label": "Date",
"type": "Date",
"readonly": true,
"format": "pattern:'dd.MM.yyyy HH:mm:ss'"
}
Decimal
:pattern
documentation can be found at javaNumberFormat
{
"name": "VALUE",
"label": "Decimal",
"type": "Decimal",
"readonly": true,
"format": "pattern:'#0.00',locale:'de'"
}
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",
"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",
"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",
"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",
"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",
"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 likeformField
.exclude
: Is used to exclude attributes with predifined values from settings likeattributeControl
.
{
"name": "myfield",
"type": "String",
"formField": true,
"dirtyCheck": "include"
},
{
"name": "myfield",
"type": "String",
"dirtyCheck": "exclude",
"attributeControl": {
"js": "setValue('Initial value');"
}
}
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,
"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 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}"
}