Input helpers
Helper functions for input
These are functions that help in generating input in a certain format that is difficult to create using regular html inputs.
@pimFilter & readPimFilter
The regular pimFilter does not support ‘or’ operator between conditions and the operator always set to ‘and’. It also does not support nested conditions. If the operator between conditions is needed or nesting of conditions then look for the pimFilterV2 helper instead
PIM api filter structure is in json format and simple input by default cannot use it in a clean way. The following functions help in generating the filters for it.
This is used at the end of the input name definition
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@pimFilter(id,in,number)">
[["id","in",[1]]]
Syntax for it is as follows:
- Name of the field in pim
- Operator: =, !=, >=, <=, in, not in, contains and startswith
- Type of the value: string, number, bool
Note that in and not in operators expect the value to be a comma separated list of values.
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@pimFilter(id,in,number)"
value='1,2,3'>
[["id","in",[1,2,3]]]
Due to json filter structure and special characters in the instructions it’s not possible to read the value back into the input fields using regular methods. For this we can use another helper function
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@pimFilter(id,in,number)"
value='{{ readPimFilter .Data.Parameters "getProductsReq" "id,in,number" }}'>
[["id","in",[1]]]
Required parameters:
- Parameters (usually .Data.Parameters)
- Name of the request
- Filter definition
We can add multiple filters to the same page, they will all be appended with the “and” operator automatically
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@pimFilter(id,in,number)"
value='{{ readPimFilter .Data.Parameters "getProductsReq" "id,in,number" }}'>
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@pimFilter(code,contains,string)"
value='{{ readPimFilter .Data.Parameters "getProductsReq" "code,contains,string" }}'>
[["id","in",[1]],"and",["code","contains","value"]]
Since . is reserved for template operators we need to define nested fields with -> instead
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@pimFilter(name->en,contains,string)"
value='{{ readPimFilter .Data.Parameters "getProductsReq" "name->en,contains,string" }}'>
[["name.en","contains","value"]]
@pimFilterV2, pimFilterOperatorV2 & readPimFilterV2
Used to help generate pim filter json type structure from html inputs. Similar to the version 1 of the pimFilter only that this one supports different operators between conditions and optionally also nesting of conditions.
Also since the ordering of the elements is important then the order helper should also be used when using the V2 variant.
Syntax for it is as follows:
- Name of the field in pim
- Operator: =, !=, >=, <=, in, not in, contains and startswith
- Type of the value: string, number, bool
- Optional. Add a nested group identifier, this is a random string value that group similar values to a nested group.
Note that in and not in operators expect the value to be a comma separated list of values.
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@{order(1);pimFilterV2(id,in,number)}">
[["id","in",[1]]]
Due to json filter structure and special characters in the instructions it’s not possible to read the value back into the input fields using regular methods. For this we can use another helper function readPimFilterV2
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@{order(1);pimFilterV2(id,in,number)}"
value='{{ readPimFilterV2 .Data.Parameters "getProductsReq" "id,in,number" }}'>
[["id","in",[1]]]
We can add multiple filters to the same page, but we also need add an operator between the conditions using the pimFilerOperatorV2 helper.
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@{order(1);pimFilterV2(id,in,number)}"
value='{{ readPimFilter .Data.Parameters "getProductsReq" "id,in,number" }}'>
<input type="hidden" name="PIMApi.Api.Query.getProductsReq.filter@{order(2);pimFilterOperatorV2()}" value="and">
<input type="text" name="PIMApi.Api.Query.getProductsReq.filter@{order(3);pimFilter(code,contains,string)}"
value='{{ readPimFilter .Data.Parameters "getProductsReq" "code,contains,string" }}'>
[["id","in",[1]],"and",["code","contains","value"]]
Optionally we can also create nested filters with the group identifier parameter. Do not forget to update the order of the functions and also the operator between possible groups.
In the sample we provide it a value of ‘a’, but the value is user defined. Everything with the value will be nested in the same array.
<input type="text" name="PIMApi.Api.Query.myRequest1.filter@{order(1);pimFilterV2(id,in,number,a)}"
value='{{ readPimFilterV2 .Data.Parameters "myRequest1" "id,in,number,a" }}'>
<input type="hidden" name="PIMApi.Api.Query.myRequest1.filter@{order(2);pimFilterOperatorV2(a)}" value="or">
<input type="text" name="PIMApi.Api.Query.myRequest1.filter@{order(3);pimFilterV2(code,contains,string,a)}"
value='{{ readPimFilterV2 .Data.Parameters "myRequest1" "code,contains,string,a" }}'>
<input type="hidden" name="PIMApi.Api.Query.myRequest1.filter@{order(4);pimFilterOperatorV2()}" value="or">
<input type="text" name="PIMApi.Api.Query.myRequest1.filter@{order(5);pimFilterV2(code2,contains,string)}"
value='{{ readPimFilterV2 .Data.Parameters "myRequest1" "code2,contains,string" }}'>
<input type="hidden" name="PIMApi.Api.Query.myRequest1.filter@{order(6);pimFilterOperatorV2()}" value="or">
<input type="text" name="PIMApi.Api.Query.myRequest1.filter@{order(7);pimFilterV2(code3,contains,string)}"
value='{{ readPimFilterV2 .Data.Parameters "myRequest1" "code3,contains,string" }}'>
[["id","in",[1]],"or",["code","contains","test"],"or",["code2","contains","test2"],"or",["code3","contains","test3"]]
Json
Functions that related to the Json
parameter type.
JSON field names may contain @
symbol, so function section definition starts with @{
and ends with }
to avoid collisions. E.g. @{order(1);foo(bar,rab)}
. Functions separated by semicolon ;
. Function
parameters separated by comma ,
.
@order
Defines the order of inputs related to the json generation process. In next sample initial structure of the json input would always be executed first and only then all other inputs. This allows us to predefine the payload of json body and then change only necessary fields.
<input type="hidden"
name="CaFaApi.Api.Json.putConf.json.@{order(1)}"
value='{"application":"my-app","level":"Company","name":"dynamic-sample","value":{}}'>
also may be used with chaining:
<input type="hidden"
name="CaFaApi.Api.Json.putConf.json.<-@{order(1)}"
value="getConfState.Response.0">
@setDefaultDate
Used to set default preset date values that have a value based on the current date. For example some api should get a default start time of today.
Parameters:
- Timezone (use ‘from-conf’ to get the timezone value from accounts configuration)
- Format for the date value (https://gosamples.dev/date-time-format-cheatsheet/) (use ‘unix’ to get the value as unix timestamp)
- (Optional) Adjust by date value (minute, hour, day, month or year)
- (Optional) Integer (negative or positive) for the adjustment value
- (Optional) Static value to suffix the formatted date on output
- (Optional) Turn the static value to a prefix instead
Note it’s important to give the preset value of “default” for the function to insert the date value. This is so that possible manual values will never be overwritten.
<input type="text" name="ReportsApi.Api.Query.myRequest1.date@{setDefaultDate(UTC,02-01-06 15:04:05 MST)}"
value="" data-preset-val="default">
With the optional date adjustment parameters.
<input type="text" name="ReportsApi.Api.Query.myRequest1.dateFrom@{setDefaultDate(UTC,02-01-06 15:04:05 MST)}"
value="" data-preset-val="default">
<input type="text" name="ReportsApi.Api.Query.myRequest1.dateTo@{setDefaultDate(UTC,02-01-06 15:04:05 MST,month,1)}"
value="" data-preset-val="default">
Using the optional suffix and prefix.
<!-- As suffix, without the 6th optional parameter -->
<input type="hidden" name="PIMApi.Api.Query.myRequest1.date@{setDefaultDate(UTC,2006-01-02,2006-01,day,0, 00:00:00)}"
value="" data-preset-val="default">
<!-- Would generate: 2024-08 00:00:00 -->
<!-- As prefix with the 6th parameter -->
<input type="hidden" name="PIMApi.Api.Query.myRequest1.date@{setDefaultDate(UTC,2006-01-02,2006-01,day,0,00:00:00 ,true)}"
value="" data-preset-val="default">
<!-- Would generate: 00:00:00 2024-08-->
It’s also possible to set the function to read the current accounts timezone configuration value instead. To do this set the timezone value to from-conf.
<input type="text" name="ReportsApi.Api.Query.myRequest1.date@{setDefaultDate(from-conf,02-01-06 15:04:05 MST)}"
value="" data-preset-val="default">
Doing this the function will look for the value from accounts configuration:timezone value, if the value is not set or has an invalid value then it defaults to UTC.
@formatDate
Used to alter the date format to formats that the possible api requires. Mostly useful when the visual representation of the value in the UI is not the same as the api requires.
For example of the api needs unix but the UI should display regular year, month and day.
Parameters:
- Timezone (use ‘from-conf’ to get the timezone value from accounts configuration)
- Format for the date value (UI) (https://gosamples.dev/date-time-format-cheatsheet/) (use ‘unix’ to get the value as unix timestamp)
- Format of the output (API) (https://gosamples.dev/date-time-format-cheatsheet/) (use ‘unix’ to set the value as unix timestamp)
- (Optional) Adjust by date value (minute, hour, day, month, year, year, dtFirstDayOfWeek, dtLastDayOfWeek, dtFirstDayOfMonth, dtLastDayOfMonth, dtFirstDayOfYear or dtLastDayOfYear)
- (Optional) Integer (negative or positive) for the adjustment value. for “dt” related types first applies adjustment then sets specific time. “dt” for weeks accepts only 0 or 1, which is bool for isSunday
- (Optional) Static value to suffix the formatted date on output
- (Optional) Turn the static value to a prefix instead
<!-- In this sample we take the value of 2024-04-25 and set it as unix timestamp when the api request is made -->
<input type="text" name="PIMApi.Api.Query.myRequest1.date@{formatDate(UTC,2006-01-02,unix)}"
value="2024-04-25">
With the optional date adjustment parameters.
<!-- In this sample we take the value of 2024-04-25, append 5 days and set it as unix timestamp when the api request is made -->
<input type="text" name="PIMApi.Api.Query.myRequest1.date@{formatDate(UTC,2006-01-02,unix,day,5)}"
value="2024-04-25">
Using the optional suffix and prefix.
<!-- As suffix, without the 7th optional parameter -->
<input type="hidden" name="PIMApi.Api.Query.myRequest1.date@{formatDate(UTC,2006-01-02,2006-01,day,0, 00:00:00)}"
data-preset-val="2024-04-25">
<!-- Would generate: 2024-08 00:00:00 -->
<!-- As prefix with the 7th parameter -->
<input type="hidden" name="PIMApi.Api.Query.myRequest1.date@{formatDate(UTC,2006-01-02,2006-01,day,0,00:00:00 ,true)}"
data-preset-val="2024-04-25">
<!-- Would generate: 00:00:00 2024-08-->
@encode
Version 1.222+
Can be used to encode the value. Supports base32, base64 and hex. Default is base64 if parameter is omitted, provide the parameter to use a different encoding.
<!-- Defaults to base64 -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{encode}"
value="some value to be encoded">
<!-- Request specific -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{encode(base64)}"
value="some value to be encoded">
<!-- Hex example -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{encode(hex)}"
value="some value to be encoded">
@decode
Version 1.222+
Can be used to decode an encoded api response value to a string (supports base32, base64 and hex). Default is base64 if parameter is omitted, provide the parameter to use a different encoding.
<!-- Defaults to base64 -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{decode}"
value="some value to be encoded">
<!-- Request specific -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{decode(base64)}"
value="some value to be encoded">
<!-- Hex example -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{decode(hex)}"
value="dGVzdA==">
@hash
Version 1.222+
Can be used to hash an api value according to an algorithm. Supports md5, sha1, sha256 and sha512. Defaults to sha1 if the parameter is not provided.
<!-- Defaults to sha1 -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{hash}"
value="some value to be encoded">
<!-- Request specific -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{hash(sha1)}"
value="some value to be encoded">
<!-- md5 example -->
<input type="text" name="ReportsApi.Api.Query.myRequest1.someData@{hash(md5)}"
value="value to be hashed">
@encrypt / @decrypt
Version 1.254+
This can be used to encrypt the data that is being saved in the api (kvs for example). This means that the data will only be readable when the correct key is provided.
The feature uses AES cipher, and the protection strength is determined by the given key length. Note that the keys need to use the correct length (16, 24 or 32)
- 16 characters : AES-128
- 24 characters : AES-192
- 32 characters : AES-256
Setting the keys to requests
Set the key for the request so the encryption knows what it needs to use.
<!--
Remember that ordering is important here as we need the system to always have the key before any encryption.
In this sample we use the chaining to take the key from the variables file, but the value can be taken from
any other api call or from a hardcoded value.
-->
<input type="hidden" name="KvsApi.Api.Encrypt.myRequest1.<-key@{order(1)}"
value="Variables.someKey" data-preset-val="Variables.someKey">
Also note that if the save and read is done on the same page then the key should be added for both calls.
Encrypting the values
Once we have set the key then we can use the encrypt helper on the values we want to protect.
<!--
Use the order here to make sure that this is done after the key set.
Any api string value can be protected like this (limited to the max length of them).
-->
<input type="text" name="KvsApi.Api.Json.myRequest1.string.value@{order(2);encrypt}"
value="some value to be encoded">
Decrypting
Remember to set the key for reading, otherwise the api will return an unreadable string.
<!-- When reading we also need to set the key -->
<input type="hidden" name="KvsApi.Api.Encrypt.myRequest2.<-key"
value="Variables.someKey" data-preset-val="Variables.someKey">
Use the decrypt tools helper to read the data.
The method will not inform you of an invalid or missing keys, instead it will generate random garbage values every single load.
<ul>
{{ range .Data.KvsApi.Api.Requests.myRequest2.Response.Array }}
<li>{{ $.Tools.Decrypt (.Get "value").String }}</li>
{{ end }}
<ul>
Sample
A simple save and read sample using kvs api.
<form method="post">
<input type="hidden" name="KvsApi.Api.Post.myRequest1"
value="api/v1/entry">
<input type="hidden" name="KvsApi.Api.Encrypt.myRequest1.<-key@{order(1)}"
value="Variables.someKey" data-preset-val="Variables.someKey">
<input type="hidden" name="KvsApi.Api.Json.myRequest1.string.topicId"
value="5afb02fc-04a5-4524-a816-4381f97b1few">
<input type="hidden" name="KvsApi.Api.Json.myRequest1.string.key"
value="my-value">
<input type="text" name="KvsApi.Api.Json.myRequest1.string.value@{order(2);encrypt}"
value="some value to be encoded">
<button type="submit">send</button>
</form>
<input type="hidden" name="KvsApi.Api.Get.myRequest2|2"
value="api/v1/entry" data-preset-val="api/v1/entry">
<input type="hidden" name="KvsApi.Api.Encrypt.myRequest2.<-key"
value="Variables.someKey" data-preset-val="Variables.someKey">
<input type="hidden" name="KvsApi.Api.Query.myRequest2.topicId"
value="1" data-preset-val="5afb02fc-04a5-4524-a816-4381f97b1few">
<br>
<ul>
{{ range .Data.KvsApi.Api.Requests.myRequest2.Response.Array }}
<li>{{ $.Tools.Decrypt (.Get "value").String }}</li>
{{ end }}
<ul>
@toArrIndexParameters
Can be used to generate multiple request parameters based on input array from another dynamic result.
For use cases where the api expects indexed requests.
For example
someValue0, someValue1 etc
someParam[0], someParam[1]
Use %v in the field name to indicate where the index is to be printed.
<input name="PIMApi.Api.Query.myRequest2.<-myField[%v]|@{toArrIndexParameters}" data-preset-val="myRequest1.Response.#.id">
In this example lets assume the result would be [1,2,3], this would be generated as 3 separate parameters for the request:
PIMApi.Api.Query.myRequest2.myField[0] = 1 PIMApi.Api.Query.myRequest2.myField[1] = 2 PIMApi.Api.Query.myRequest2.myField[2] = 3
@wrap
Basically wraps entire content into provided suffix and prefix. This function always accepts two parameters, if there is more or less than two, then initial value is returned.
<input type="hidden" name="KvsApi.Api.Json.test.string.field1@{wrap([,])}" value='"one","two","three"'>
<!-- Result: ["one","two","three"] -->
@prefix
Prefixes the value with given string.
<input type="hidden" name="KvsApi.Api.Json.test.string.field1@{prefix(hello )}" value='world'>
<!-- Result: hello world -->
@suffix
Adds suffix to the value.
<input type="hidden" name="KvsApi.Api.Json.test.string.field1@{prefix( world)}" value='hello'>
<!-- Result: hello world -->